Merge "Add an API to manually invoke Android Beam."
diff --git a/Android.mk b/Android.mk
index d478a59..57091cc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -183,6 +183,7 @@
core/java/android/print/IWriteResultCallback.aidl \
core/java/android/printservice/IPrintService.aidl \
core/java/android/printservice/IPrintServiceClient.aidl \
+ core/java/android/service/dreams/IDozeHardware.aidl \
core/java/android/service/dreams/IDreamManager.aidl \
core/java/android/service/dreams/IDreamService.aidl \
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
@@ -260,12 +261,17 @@
media/java/android/media/IAudioService.aidl \
media/java/android/media/IAudioFocusDispatcher.aidl \
media/java/android/media/IAudioRoutesObserver.aidl \
+ media/java/android/media/IMediaController.aidl \
+ media/java/android/media/IMediaControllerCallback.aidl \
media/java/android/media/IMediaHTTPConnection.aidl \
media/java/android/media/IMediaHTTPService.aidl \
media/java/android/media/IMediaRouterClient.aidl \
media/java/android/media/IMediaRouterService.aidl \
media/java/android/media/IMediaScannerListener.aidl \
media/java/android/media/IMediaScannerService.aidl \
+ media/java/android/media/IMediaSession.aidl \
+ media/java/android/media/IMediaSessionCallback.aidl \
+ media/java/android/media/IMediaSessionManager.aidl \
media/java/android/media/IRemoteControlClient.aidl \
media/java/android/media/IRemoteControlDisplay.aidl \
media/java/android/media/IRemoteDisplayCallback.aidl \
@@ -275,9 +281,6 @@
telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl \
telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
telephony/java/com/android/internal/telephony/ITelephony.aidl \
- telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl \
- telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl \
- telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl \
telephony/java/com/android/internal/telephony/ISms.aidl \
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
@@ -576,7 +579,9 @@
-samplegroup Content \
-samplegroup Input \
-samplegroup Media \
+ -samplegroup RenderScript \
-samplegroup Security \
+ -samplegroup Sensors \
-samplegroup Testing \
-samplegroup UI \
-samplegroup Views
diff --git a/api/current.txt b/api/current.txt
index 9492d56..35afb73 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -345,6 +345,7 @@
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
field public static final int candidatesTextStyleSpans = 16843312; // 0x1010230
field public static final deprecated int capitalize = 16843113; // 0x1010169
+ field public static final int castsShadow = 16843777; // 0x1010401
field public static final int category = 16843752; // 0x10103e8
field public static final int centerBright = 16842956; // 0x10100cc
field public static final int centerColor = 16843275; // 0x101020b
@@ -378,8 +379,6 @@
field public static final int colorActivatedHighlight = 16843664; // 0x1010390
field public static final int colorBackground = 16842801; // 0x1010031
field public static final int colorBackgroundCacheHint = 16843435; // 0x10102ab
- field public static final int colorFilterColor = 16843767; // 0x10103f7
- field public static final int colorFilterMode = 16843768; // 0x10103f8
field public static final int colorFocusedHighlight = 16843663; // 0x101038f
field public static final int colorForeground = 16842800; // 0x1010030
field public static final int colorForegroundInverse = 16843270; // 0x1010206
@@ -400,10 +399,10 @@
field public static final int content = 16843355; // 0x101025b
field public static final int contentAuthority = 16843408; // 0x1010290
field public static final int contentDescription = 16843379; // 0x1010273
- field public static final int controlX1 = 16843770; // 0x10103fa
- field public static final int controlX2 = 16843772; // 0x10103fc
- field public static final int controlY1 = 16843771; // 0x10103fb
- field public static final int controlY2 = 16843773; // 0x10103fd
+ field public static final int controlX1 = 16843769; // 0x10103f9
+ field public static final int controlX2 = 16843771; // 0x10103fb
+ field public static final int controlY1 = 16843770; // 0x10103fa
+ field public static final int controlY2 = 16843772; // 0x10103fc
field public static final int cropToPadding = 16843043; // 0x1010123
field public static final int cursorVisible = 16843090; // 0x1010152
field public static final int customNavigationLayout = 16843474; // 0x10102d2
@@ -543,7 +542,7 @@
field public static final int fromAlpha = 16843210; // 0x10101ca
field public static final int fromDegrees = 16843187; // 0x10101b3
field public static final int fromScene = 16843741; // 0x10103dd
- field public static final int fromSceneName = 16843774; // 0x10103fe
+ field public static final int fromSceneName = 16843773; // 0x10103fd
field public static final int fromXDelta = 16843206; // 0x10101c6
field public static final int fromXScale = 16843202; // 0x10101c2
field public static final int fromYDelta = 16843208; // 0x10101c8
@@ -638,7 +637,7 @@
field public static final int isScrollContainer = 16843342; // 0x101024e
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
- field public static final int isolatedZVolume = 16843769; // 0x10103f9
+ field public static final int isolatedZVolume = 16843768; // 0x10103f8
field public static final int itemBackground = 16843056; // 0x1010130
field public static final int itemIconDisabledAlpha = 16843057; // 0x1010131
field public static final int itemPadding = 16843565; // 0x101032d
@@ -891,6 +890,7 @@
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
+ field public static final int requiredForProfile = 16843778; // 0x1010402
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeMode = 16843619; // 0x1010363
@@ -961,7 +961,7 @@
field public static final int shadowRadius = 16843108; // 0x1010164
field public static final int shape = 16843162; // 0x101019a
field public static final int shareInterpolator = 16843195; // 0x10101bb
- field public static final int sharedElementName = 16843776; // 0x1010400
+ field public static final int sharedElementName = 16843775; // 0x10103ff
field public static final int sharedUserId = 16842763; // 0x101000b
field public static final int sharedUserLabel = 16843361; // 0x1010261
field public static final int shouldDisableView = 16843246; // 0x10101ee
@@ -1138,13 +1138,14 @@
field public static final int tileMode = 16843265; // 0x1010201
field public static final int timeZone = 16843724; // 0x10103cc
field public static final int tint = 16843041; // 0x1010121
+ field public static final int tintMode = 16843767; // 0x10103f7
field public static final int title = 16843233; // 0x10101e1
field public static final int titleCondensed = 16843234; // 0x10101e2
field public static final int titleTextStyle = 16843512; // 0x10102f8
field public static final int toAlpha = 16843211; // 0x10101cb
field public static final int toDegrees = 16843188; // 0x10101b4
field public static final int toScene = 16843742; // 0x10103de
- field public static final int toSceneName = 16843775; // 0x10103ff
+ field public static final int toSceneName = 16843774; // 0x10103fe
field public static final int toXDelta = 16843207; // 0x10101c7
field public static final int toXScale = 16843203; // 0x10101c3
field public static final int toYDelta = 16843209; // 0x10101c9
@@ -1160,7 +1161,7 @@
field public static final int transformPivotX = 16843552; // 0x1010320
field public static final int transformPivotY = 16843553; // 0x1010321
field public static final int transition = 16843743; // 0x10103df
- field public static final int transitionGroup = 16843777; // 0x1010401
+ field public static final int transitionGroup = 16843776; // 0x1010400
field public static final int transitionOrdering = 16843744; // 0x10103e0
field public static final int translationX = 16843554; // 0x1010322
field public static final int translationY = 16843555; // 0x1010323
@@ -4749,6 +4750,8 @@
}
public class DevicePolicyManager {
+ method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
+ method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
method public java.util.List<android.content.ComponentName> getActiveAdmins();
method public boolean getCameraDisabled(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
@@ -6118,6 +6121,7 @@
method public final void unregisterContentObserver(android.database.ContentObserver);
method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
method public static void validateSyncExtrasBundle(android.os.Bundle);
+ field public static final java.lang.String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
field public static final java.lang.String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
field public static final java.lang.String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
@@ -6316,6 +6320,7 @@
field public static final java.lang.String LAYOUT_INFLATER_SERVICE = "layout_inflater";
field public static final java.lang.String LOCATION_SERVICE = "location";
field public static final java.lang.String MEDIA_ROUTER_SERVICE = "media_router";
+ field public static final java.lang.String MEDIA_SESSION_SERVICE = "media_session";
field public static final int MODE_APPEND = 32768; // 0x8000
field public static final int MODE_ENABLE_WRITE_AHEAD_LOGGING = 8; // 0x8
field public static final int MODE_MULTI_PROCESS = 4; // 0x4
@@ -7614,6 +7619,7 @@
field public static final java.lang.String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT";
field public static final java.lang.String FEATURE_APP_WIDGETS = "android.software.app_widgets";
field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
+ field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
field public static final java.lang.String FEATURE_BLUETOOTH_LE = "android.hardware.bluetooth_le";
field public static final java.lang.String FEATURE_CAMERA = "android.hardware.camera";
@@ -7635,6 +7641,7 @@
field public static final java.lang.String FEATURE_MICROPHONE = "android.hardware.microphone";
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
+ field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
@@ -7657,6 +7664,7 @@
field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
+ field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
field public static final int GET_ACTIVITIES = 1; // 0x1
@@ -10404,6 +10412,8 @@
method public void setTileModeX(android.graphics.Shader.TileMode);
method public void setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode);
method public final void setTileModeY(android.graphics.Shader.TileMode);
+ method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -10542,9 +10552,9 @@
ctor public GradientDrawable();
ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
method public void draw(android.graphics.Canvas);
+ method public float getGradientRadius();
method public int getOpacity();
method public android.graphics.drawable.GradientDrawable.Orientation getOrientation();
- method public boolean onStateChange(int[]);
method public void setAlpha(int);
method public void setColor(int);
method public void setColor(android.content.res.ColorStateList);
@@ -10639,6 +10649,8 @@
method public void setTargetDensity(android.graphics.Canvas);
method public void setTargetDensity(android.util.DisplayMetrics);
method public void setTargetDensity(int);
+ method public void setTint(android.content.res.ColorStateList);
+ method public void setTintMode(android.graphics.PorterDuff.Mode);
}
public class PaintDrawable extends android.graphics.drawable.ShapeDrawable {
@@ -11302,6 +11314,7 @@
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_PROFILE_HUE_SAT_MAP_DIMENSIONS;
@@ -11322,10 +11335,12 @@
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;
+ 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
field public static final int TEMPLATE_STILL_CAPTURE = 2; // 0x2
field public static final int TEMPLATE_VIDEO_SNAPSHOT = 4; // 0x4
+ field public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5; // 0x5
}
public static abstract class CameraDevice.CaptureListener {
@@ -11487,6 +11502,25 @@
field public static final int REQUEST_AVAILABLE_CAPABILITIES_ZSL = 4; // 0x4
field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT = 1; // 0x1
field public static final int SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT = 0; // 0x0
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_CLOUDY_WEATHER = 10; // 0xa
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_COOL_WHITE_FLUORESCENT = 14; // 0xe
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D50 = 23; // 0x17
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D55 = 20; // 0x14
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D65 = 21; // 0x15
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_D75 = 22; // 0x16
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT = 1; // 0x1
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT_FLUORESCENT = 12; // 0xc
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_DAY_WHITE_FLUORESCENT = 13; // 0xd
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_FINE_WEATHER = 9; // 0x9
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_FLASH = 4; // 0x4
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_FLUORESCENT = 2; // 0x2
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_ISO_STUDIO_TUNGSTEN = 24; // 0x18
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_SHADE = 11; // 0xb
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_A = 17; // 0x11
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_B = 18; // 0x12
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_C = 19; // 0x13
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_TUNGSTEN = 3; // 0x3
+ field public static final int SENSOR_REFERENCE_ILLUMINANT_WHITE_FLUORESCENT = 15; // 0xf
field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS = 2; // 0x2
field public static final int SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY = 3; // 0x3
field public static final int SENSOR_TEST_PATTERN_MODE_CUSTOM1 = 256; // 0x100
@@ -11637,9 +11671,11 @@
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_EXPOSURE_TIME;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FORWARD_MATRIX;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_FRAME_DURATION;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_GREEN_SPLIT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_NEUTRAL_COLOR_POINT;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP;
field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_TONE_CURVE;
+ field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_REFERENCE_ILLUMINANT;
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_MODE;
@@ -13149,6 +13185,23 @@
method public static final android.media.MediaCodecInfo getCodecInfoAt(int);
}
+ public final class MediaController {
+ ctor public MediaController(android.media.MediaSessionToken);
+ method public void addCallback(android.media.MediaController.Callback);
+ method public void addCallback(android.media.MediaController.Callback, android.os.Handler);
+ method public void removeCallback(android.media.MediaController.Callback);
+ method public void sendCommand(java.lang.String, android.os.Bundle);
+ method public void sendMediaButton(int);
+ }
+
+ public static abstract class MediaController.Callback {
+ ctor public MediaController.Callback();
+ method public void onEvent(java.lang.String, android.os.Bundle);
+ method public void onMetadataUpdate(android.os.Bundle);
+ method public void onPlaybackStateChange(int);
+ method public void onRouteChanged(android.os.Bundle);
+ }
+
public final class MediaCrypto {
ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
method public static final boolean isCryptoSchemeSupported(java.util.UUID);
@@ -13715,6 +13768,33 @@
method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
}
+ public final class MediaSession {
+ method public void addCallback(android.media.MediaSession.Callback);
+ method public void addCallback(android.media.MediaSession.Callback, android.os.Handler);
+ method public android.media.MediaSessionToken getSessionToken();
+ method public void release();
+ method public void removeCallback(android.media.MediaSession.Callback);
+ method public void setPlaybackState(int);
+ }
+
+ public static abstract class MediaSession.Callback {
+ ctor public MediaSession.Callback();
+ method public void onCommand(java.lang.String, android.os.Bundle);
+ method public void onMediaButton(android.content.Intent);
+ method public void onRequestRouteChange(android.os.Bundle);
+ }
+
+ public final class MediaSessionManager {
+ method public android.media.MediaSession createSession(java.lang.String);
+ method public java.util.List<android.media.MediaController> getActiveSessions();
+ }
+
+ public class MediaSessionToken implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator CREATOR;
+ }
+
public class MediaSyncEvent {
method public static android.media.MediaSyncEvent createEvent(int) throws java.lang.IllegalArgumentException;
method public int getAudioSessionId();
@@ -17145,11 +17225,9 @@
method public static void glGenTextures(int, java.nio.IntBuffer);
method public static void glGenerateMipmap(int);
method public static void glGetActiveAttrib(int, int, int, int[], int, int[], int, int[], int, byte[], int);
- method public static void glGetActiveAttrib(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
method public static java.lang.String glGetActiveAttrib(int, int, int[], int, int[], int);
method public static java.lang.String glGetActiveAttrib(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
method public static void glGetActiveUniform(int, int, int, int[], int, int[], int, int[], int, byte[], int);
- method public static void glGetActiveUniform(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
method public static java.lang.String glGetActiveUniform(int, int, int[], int, int[], int);
method public static java.lang.String glGetActiveUniform(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
method public static void glGetAttachedShaders(int, int, int[], int, int[], int);
@@ -17175,7 +17253,6 @@
method public static void glGetShaderPrecisionFormat(int, int, int[], int, int[], int);
method public static void glGetShaderPrecisionFormat(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
method public static void glGetShaderSource(int, int, int[], int, byte[], int);
- method public static void glGetShaderSource(int, int, java.nio.IntBuffer, byte);
method public static java.lang.String glGetShaderSource(int);
method public static void glGetShaderiv(int, int, int[], int);
method public static void glGetShaderiv(int, int, java.nio.IntBuffer);
@@ -21595,6 +21672,8 @@
field public static final java.lang.String EXTRA_MEDIA_ALBUM = "android.intent.extra.album";
field public static final java.lang.String EXTRA_MEDIA_ARTIST = "android.intent.extra.artist";
field public static final java.lang.String EXTRA_MEDIA_FOCUS = "android.intent.extra.focus";
+ field public static final java.lang.String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
+ field public static final java.lang.String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
field public static final java.lang.String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
field public static final java.lang.String EXTRA_OUTPUT = "output";
field public static final java.lang.String EXTRA_SCREEN_ORIENTATION = "android.intent.extra.screenOrientation";
@@ -21713,6 +21792,7 @@
method public static android.net.Uri getContentUriForPath(java.lang.String);
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
field public static final java.lang.String DEFAULT_SORT_ORDER = "title_key";
+ field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
field public static final android.net.Uri EXTERNAL_CONTENT_URI;
field public static final java.lang.String EXTRA_MAX_BYTES = "android.provider.MediaStore.extra.MAX_BYTES";
field public static final android.net.Uri INTERNAL_CONTENT_URI;
@@ -21748,6 +21828,11 @@
field public static final java.lang.String NAME = "name";
}
+ public static final class MediaStore.Audio.Radio {
+ ctor public MediaStore.Audio.Radio();
+ field public static final java.lang.String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
+ }
+
public static final class MediaStore.Files {
ctor public MediaStore.Files();
method public static android.net.Uri getContentUri(java.lang.String);
@@ -24567,32 +24652,6 @@
field public static final int SIM_STATE_UNKNOWN = 0; // 0x0
}
- public class ThirdPartyCallListener {
- ctor public ThirdPartyCallListener(com.android.internal.telephony.IThirdPartyCallListener);
- method public void onCallEnded(int);
- method public void onCallEstablished();
- method public void onCallProviderAttached(android.telephony.ThirdPartyCallProvider);
- method public void onRingingStarted();
- field public static final int CALL_END_INCOMING_MISSED = 2; // 0x2
- field public static final int CALL_END_NORMAL = 1; // 0x1
- field public static final int CALL_END_OTHER = 3; // 0x3
- }
-
- public class ThirdPartyCallProvider {
- ctor public ThirdPartyCallProvider();
- method public void hangup();
- method public void incomingCallAccept();
- method public void mute(boolean);
- method public void sendDtmf(char);
- }
-
- public class ThirdPartyCallService {
- ctor public ThirdPartyCallService();
- method public android.os.IBinder getBinder();
- method public void incomingCallAttach(android.telephony.ThirdPartyCallListener, java.lang.String);
- method public void outgoingCallInitiate(android.telephony.ThirdPartyCallListener, java.lang.String);
- }
-
}
package android.telephony.cdma {
@@ -27124,6 +27183,7 @@
method public final V put(K, V);
method public final synchronized int putCount();
method public final V remove(K);
+ method public void resize(int);
method public final synchronized int size();
method protected int sizeOf(K, V);
method public final synchronized java.util.Map<K, V> snapshot();
@@ -28713,7 +28773,9 @@
method protected float getBottomFadingEdgeStrength();
method protected int getBottomPaddingOffset();
method public float getCameraDistance();
+ method public final boolean getCastsShadow();
method public android.graphics.Rect getClipBounds();
+ method public final boolean getClipToOutline();
method public java.lang.CharSequence getContentDescription();
method public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
@@ -28765,6 +28827,7 @@
method public int getNextFocusRightId();
method public int getNextFocusUpId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
+ method public final void getOutline(android.graphics.Path);
method public int getOverScrollMode();
method public android.view.ViewOverlay getOverlay();
method public int getPaddingBottom();
@@ -28980,8 +29043,10 @@
method public void setBackgroundResource(int);
method public final void setBottom(int);
method public void setCameraDistance(float);
+ method public void setCastsShadow(boolean);
method public void setClickable(boolean);
method public void setClipBounds(android.graphics.Rect);
+ method public void setClipToOutline(boolean);
method public void setContentDescription(java.lang.CharSequence);
method public void setDrawingCacheBackgroundColor(int);
method public void setDrawingCacheEnabled(boolean);
@@ -29027,6 +29092,7 @@
method public void setOnLongClickListener(android.view.View.OnLongClickListener);
method public void setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener);
method public void setOnTouchListener(android.view.View.OnTouchListener);
+ method public void setOutline(android.graphics.Path);
method public void setOverScrollMode(int);
method public void setPadding(int, int, int, int);
method public void setPaddingRelative(int, int, int, int);
@@ -30223,6 +30289,7 @@
field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
+ field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
field public static final int ACTION_CLEAR_ACCESSIBILITY_FOCUS = 128; // 0x80
field public static final int ACTION_CLEAR_FOCUS = 2; // 0x2
field public static final int ACTION_CLEAR_SELECTION = 8; // 0x8
@@ -30243,6 +30310,7 @@
field public static final int ACTION_SCROLL_FORWARD = 4096; // 0x1000
field public static final int ACTION_SELECT = 4; // 0x4
field public static final int ACTION_SET_SELECTION = 131072; // 0x20000
+ field public static final int ACTION_SET_TEXT = 2097152; // 0x200000
field public static final android.os.Parcelable.Creator CREATOR;
field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2
field public static final int FOCUS_INPUT = 1; // 0x1
@@ -30256,8 +30324,13 @@
public static final class AccessibilityNodeInfo.CollectionInfo {
method public int getColumnCount();
method public int getRowCount();
+ method public int getSelectionMode();
method public boolean isHierarchical();
method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean);
+ method public static android.view.accessibility.AccessibilityNodeInfo.CollectionInfo obtain(int, int, boolean, int);
+ field public static final int SELECTION_MODE_MULTIPLE = 2; // 0x2
+ field public static final int SELECTION_MODE_NONE = 0; // 0x0
+ field public static final int SELECTION_MODE_SINGLE = 1; // 0x1
}
public static final class AccessibilityNodeInfo.CollectionItemInfo {
@@ -30266,7 +30339,9 @@
method public int getRowIndex();
method public int getRowSpan();
method public boolean isHeading();
+ method public boolean isSelected();
method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean);
+ method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean);
}
public static final class AccessibilityNodeInfo.RangeInfo {
@@ -31678,6 +31753,7 @@
method public void setRemoteViewsAdapter(android.content.Intent);
method public void setScrollIndicators(android.view.View, android.view.View);
method public void setScrollingCacheEnabled(boolean);
+ method public void setSelectionFromTop(int, int);
method public void setSelector(int);
method public void setSelector(android.graphics.drawable.Drawable);
method public void setSmoothScrollbarEnabled(boolean);
@@ -32793,7 +32869,6 @@
method public void setOverscrollHeader(android.graphics.drawable.Drawable);
method public void setSelection(int);
method public void setSelectionAfterHeaderView();
- method public void setSelectionFromTop(int, int);
method public void smoothScrollByOffset(int);
}
@@ -34069,24 +34144,6 @@
}
-package com.android.internal.telephony {
-
- public abstract interface IThirdPartyCallListener implements android.os.IInterface {
- method public abstract void onCallEnded(int) throws android.os.RemoteException;
- method public abstract void onCallEstablished() throws android.os.RemoteException;
- method public abstract void onCallProviderAttached(com.android.internal.telephony.IThirdPartyCallProvider) throws android.os.RemoteException;
- method public abstract void onRingingStarted() throws android.os.RemoteException;
- }
-
- public abstract interface IThirdPartyCallProvider implements android.os.IInterface {
- method public abstract void hangup() throws android.os.RemoteException;
- method public abstract void incomingCallAccept() throws android.os.RemoteException;
- method public abstract void mute(boolean) throws android.os.RemoteException;
- method public abstract void sendDtmf(char) throws android.os.RemoteException;
- }
-
-}
-
package com.android.internal.util {
public abstract interface Predicate {
diff --git a/cmds/idmap/Android.mk b/cmds/idmap/Android.mk
new file mode 100644
index 0000000..ffa83f2
--- /dev/null
+++ b/cmds/idmap/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := idmap.cpp create.cpp scan.cpp inspect.cpp
+
+LOCAL_SHARED_LIBRARIES := liblog libutils libandroidfw
+
+LOCAL_MODULE := idmap
+
+LOCAL_C_INCLUDES := external/zlib
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
new file mode 100644
index 0000000..ae35f7b
--- /dev/null
+++ b/cmds/idmap/create.cpp
@@ -0,0 +1,222 @@
+#include "idmap.h"
+
+#include <UniquePtr.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <androidfw/ZipFileRO.h>
+#include <utils/String8.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+using namespace android;
+
+namespace {
+ int get_zip_entry_crc(const char *zip_path, const char *entry_name, uint32_t *crc)
+ {
+ UniquePtr<ZipFileRO> zip(ZipFileRO::open(zip_path));
+ if (zip.get() == NULL) {
+ return -1;
+ }
+ ZipEntryRO entry = zip->findEntryByName(entry_name);
+ if (entry == NULL) {
+ return -1;
+ }
+ if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)crc)) {
+ return -1;
+ }
+ zip->releaseEntry(entry);
+ return 0;
+ }
+
+ int open_idmap(const char *path)
+ {
+ int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644));
+ if (fd == -1) {
+ ALOGD("error: open %s: %s\n", path, strerror(errno));
+ goto fail;
+ }
+ if (fchmod(fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
+ ALOGD("error: fchmod %s: %s\n", path, strerror(errno));
+ goto fail;
+ }
+ if (TEMP_FAILURE_RETRY(flock(fd, LOCK_EX | LOCK_NB)) != 0) {
+ ALOGD("error: flock %s: %s\n", path, strerror(errno));
+ goto fail;
+ }
+
+ return fd;
+fail:
+ if (fd != -1) {
+ close(fd);
+ unlink(path);
+ }
+ return -1;
+ }
+
+ int write_idmap(int fd, const uint32_t *data, size_t size)
+ {
+ if (lseek(fd, SEEK_SET, 0) < 0) {
+ return -1;
+ }
+ size_t bytesLeft = size;
+ while (bytesLeft > 0) {
+ ssize_t w = TEMP_FAILURE_RETRY(write(fd, data + size - bytesLeft, bytesLeft));
+ if (w < 0) {
+ fprintf(stderr, "error: write: %s\n", strerror(errno));
+ return -1;
+ }
+ bytesLeft -= w;
+ }
+ return 0;
+ }
+
+ bool is_idmap_stale_fd(const char *target_apk_path, const char *overlay_apk_path, int idmap_fd)
+ {
+ static const size_t N = ResTable::IDMAP_HEADER_SIZE_BYTES;
+ struct stat st;
+ if (fstat(idmap_fd, &st) == -1) {
+ return true;
+ }
+ if (st.st_size < N) {
+ // file is empty or corrupt
+ return true;
+ }
+
+ char buf[N];
+ ssize_t bytesLeft = N;
+ if (lseek(idmap_fd, SEEK_SET, 0) < 0) {
+ return true;
+ }
+ for (;;) {
+ ssize_t r = TEMP_FAILURE_RETRY(read(idmap_fd, buf + N - bytesLeft, bytesLeft));
+ if (r < 0) {
+ return true;
+ }
+ bytesLeft -= r;
+ if (bytesLeft == 0) {
+ break;
+ }
+ if (r == 0) {
+ // "shouldn't happen"
+ return true;
+ }
+ }
+
+ uint32_t cached_target_crc, cached_overlay_crc;
+ String8 cached_target_path, cached_overlay_path;
+ if (!ResTable::getIdmapInfo(buf, N, &cached_target_crc, &cached_overlay_crc,
+ &cached_target_path, &cached_overlay_path)) {
+ return true;
+ }
+
+ if (cached_target_path != target_apk_path) {
+ return true;
+ }
+ if (cached_overlay_path != overlay_apk_path) {
+ return true;
+ }
+
+ uint32_t actual_target_crc, actual_overlay_crc;
+ if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
+ &actual_target_crc) == -1) {
+ return true;
+ }
+ if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
+ &actual_overlay_crc) == -1) {
+ return true;
+ }
+
+ return cached_target_crc != actual_target_crc || cached_overlay_crc != actual_overlay_crc;
+ }
+
+ bool is_idmap_stale_path(const char *target_apk_path, const char *overlay_apk_path,
+ const char *idmap_path)
+ {
+ struct stat st;
+ if (stat(idmap_path, &st) == -1) {
+ // non-existing idmap is always stale; on other errors, abort idmap generation
+ return errno == ENOENT;
+ }
+
+ int idmap_fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY));
+ if (idmap_fd == -1) {
+ return false;
+ }
+ bool is_stale = is_idmap_stale_fd(target_apk_path, overlay_apk_path, idmap_fd);
+ close(idmap_fd);
+ return is_stale;
+ }
+
+ int create_idmap(const char *target_apk_path, const char *overlay_apk_path,
+ uint32_t **data, size_t *size)
+ {
+ uint32_t target_crc, overlay_crc;
+ if (get_zip_entry_crc(target_apk_path, AssetManager::RESOURCES_FILENAME,
+ &target_crc) == -1) {
+ return -1;
+ }
+ if (get_zip_entry_crc(overlay_apk_path, AssetManager::RESOURCES_FILENAME,
+ &overlay_crc) == -1) {
+ return -1;
+ }
+
+ AssetManager am;
+ bool b = am.createIdmap(target_apk_path, overlay_apk_path, target_crc, overlay_crc,
+ data, size);
+ return b ? 0 : -1;
+ }
+
+ int create_and_write_idmap(const char *target_apk_path, const char *overlay_apk_path,
+ int fd, bool check_if_stale)
+ {
+ if (check_if_stale) {
+ if (!is_idmap_stale_fd(target_apk_path, overlay_apk_path, fd)) {
+ // already up to date -- nothing to do
+ return 0;
+ }
+ }
+
+ uint32_t *data = NULL;
+ size_t size;
+
+ if (create_idmap(target_apk_path, overlay_apk_path, &data, &size) == -1) {
+ return -1;
+ }
+
+ if (write_idmap(fd, data, size) == -1) {
+ free(data);
+ return -1;
+ }
+
+ free(data);
+ return 0;
+ }
+}
+
+int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
+ const char *idmap_path)
+{
+ if (!is_idmap_stale_path(target_apk_path, overlay_apk_path, idmap_path)) {
+ // already up to date -- nothing to do
+ return EXIT_SUCCESS;
+ }
+
+ int fd = open_idmap(idmap_path);
+ if (fd == -1) {
+ return EXIT_FAILURE;
+ }
+
+ int r = create_and_write_idmap(target_apk_path, overlay_apk_path, fd, false);
+ close(fd);
+ if (r != 0) {
+ unlink(idmap_path);
+ }
+ return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd)
+{
+ return create_and_write_idmap(target_apk_path, overlay_apk_path, fd, true) == 0 ?
+ EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
new file mode 100644
index 0000000..46c0edc
--- /dev/null
+++ b/cmds/idmap/idmap.cpp
@@ -0,0 +1,237 @@
+#include "idmap.h"
+
+#include <private/android_filesystem_config.h> // for AID_SYSTEM
+
+#include <stdlib.h>
+#include <string.h>
+
+namespace {
+ const char *usage = "NAME\n\
+ idmap - create or display idmap files\n\
+\n\
+SYNOPSIS \n\
+ idmap --help \n\
+ idmap --fd target overlay fd \n\
+ idmap --path target overlay idmap \n\
+ idmap --scan dir-to-scan target-to-look-for target dir-to-hold-idmaps \n\
+ idmap --inspect idmap \n\
+\n\
+DESCRIPTION \n\
+ Idmap files play an integral part in the runtime resource overlay framework. An idmap \n\
+ file contains a mapping of resource identifiers between overlay package and its target \n\
+ package; this mapping is used during resource lookup. Idmap files also act as control \n\
+ files by their existence: if not present, the corresponding overlay package is ignored \n\
+ when the resource context is created. \n\
+\n\
+ Idmap files are stored in /data/resource-cache. For each pair (target package, overlay \n\
+ package), there exists exactly one idmap file, or none if the overlay should not be used. \n\
+\n\
+NOMENCLATURE \n\
+ target: the original, non-overlay, package. Each target package may be associated with \n\
+ any number of overlay packages. \n\
+\n\
+ overlay: an overlay package. Each overlay package is associated with exactly one target \n\
+ package, specified in the overlay's manifest using the <overlay target=\"...\"/> \n\
+ tag. \n\
+\n\
+OPTIONS \n\
+ --help: display this help \n\
+\n\
+ --fd: create idmap for target package 'target' (path to apk) and overlay package 'overlay' \n\
+ (path to apk); write results to file descriptor 'fd' (integer). This invocation \n\
+ version is intended to be used by a parent process with higher privileges to call \n\
+ idmap in a controlled way: the parent will open a suitable file descriptor, fork, \n\
+ drop its privileges and exec. This tool will continue execution without the extra \n\
+ privileges, but still have write access to a file it could not have opened on its \n\
+ own. \n\
+\n\
+ --path: create idmap for target package 'target' (path to apk) and overlay package \n\
+ 'overlay' (path to apk); write results to 'idmap' (path). \n\
+\n\
+ --scan: non-recursively search directory 'dir-to-scan' (path) for overlay packages with \n\
+ target package 'target-to-look-for' (package name) present at 'target' (path to \n\
+ apk). For each overlay package found, create an idmap file in 'dir-to-hold-idmaps' \n\
+ (path). \n\
+\n\
+ --inspect: decode the binary format of 'idmap' (path) and display the contents in a \n\
+ debug-friendly format. \n\
+\n\
+EXAMPLES \n\
+ Create an idmap file: \n\
+\n\
+ $ adb shell idmap --path /system/app/target.apk \\ \n\
+ /vendor/overlay/overlay.apk \\ \n\
+ /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\
+\n\
+ Display an idmap file: \n\
+\n\
+ $ adb shell idmap --inspect /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\
+ SECTION ENTRY VALUE OFFSET COMMENT \n\
+ IDMAP HEADER magic 0x706d6469 0x0 \n\
+ base crc 0x484aa77f 0x1 \n\
+ overlay crc 0x03c66fa5 0x2 \n\
+ base path .......... 0x03-0x42 /system/app/target.apk \n\
+ overlay path .......... 0x43-0x82 /vendor/overlay/overlay.apk \n\
+ DATA HEADER types count 0x00000003 0x83 \n\
+ padding 0x00000000 0x84 \n\
+ type offset 0x00000004 0x85 absolute offset 0x87, xml \n\
+ type offset 0x00000007 0x86 absolute offset 0x8a, string \n\
+ DATA BLOCK entry count 0x00000001 0x87 \n\
+ entry offset 0x00000000 0x88 \n\
+ entry 0x7f020000 0x89 xml/integer \n\
+ DATA BLOCK entry count 0x00000002 0x8a \n\
+ entry offset 0x00000000 0x8b \n\
+ entry 0x7f030000 0x8c string/str \n\
+ entry 0x7f030001 0x8d string/str2 \n\
+\n\
+ In this example, the overlay package provides three alternative resource values:\n\
+ xml/integer, string/str and string/str2.\n\
+\n\
+NOTES \n\
+ This tool and its expected invocation from installd is modelled on dexopt.";
+
+ bool verify_directory_readable(const char *path)
+ {
+ return access(path, R_OK | X_OK) == 0;
+ }
+
+ bool verify_directory_writable(const char *path)
+ {
+ return access(path, W_OK) == 0;
+ }
+
+ bool verify_file_readable(const char *path)
+ {
+ return access(path, R_OK) == 0;
+ }
+
+ bool verify_root_or_system()
+ {
+ uid_t uid = getuid();
+ gid_t gid = getgid();
+
+ return (uid == 0 && gid == 0) || (uid == AID_SYSTEM && gid == AID_SYSTEM);
+ }
+
+ int maybe_create_fd(const char *target_apk_path, const char *overlay_apk_path,
+ const char *idmap_str)
+ {
+ // anyone (not just root or system) may do --fd -- the file has
+ // already been opened by someone else on our behalf
+
+ char *endptr;
+ int idmap_fd = strtol(idmap_str, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: failed to parse file descriptor argument %s\n", idmap_str);
+ return -1;
+ }
+
+ if (!verify_file_readable(target_apk_path)) {
+ ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno));
+ return -1;
+ }
+
+ if (!verify_file_readable(overlay_apk_path)) {
+ ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno));
+ return -1;
+ }
+
+ return idmap_create_fd(target_apk_path, overlay_apk_path, idmap_fd);
+ }
+
+ int maybe_create_path(const char *target_apk_path, const char *overlay_apk_path,
+ const char *idmap_path)
+ {
+ if (!verify_root_or_system()) {
+ fprintf(stderr, "error: permission denied: not user root or user system\n");
+ return -1;
+ }
+
+ if (!verify_file_readable(target_apk_path)) {
+ ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno));
+ return -1;
+ }
+
+ if (!verify_file_readable(overlay_apk_path)) {
+ ALOGD("error: failed to read apk %s: %s\n", overlay_apk_path, strerror(errno));
+ return -1;
+ }
+
+ return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path);
+ }
+
+ int maybe_scan(const char *overlay_dir, const char *target_package_name,
+ const char *target_apk_path, const char *idmap_dir)
+ {
+ if (!verify_root_or_system()) {
+ fprintf(stderr, "error: permission denied: not user root or user system\n");
+ return -1;
+ }
+
+ if (!verify_directory_readable(overlay_dir)) {
+ ALOGD("error: no read access to %s: %s\n", overlay_dir, strerror(errno));
+ return -1;
+ }
+
+ if (!verify_file_readable(target_apk_path)) {
+ ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno));
+ return -1;
+ }
+
+ if (!verify_directory_writable(idmap_dir)) {
+ ALOGD("error: no write access to %s: %s\n", idmap_dir, strerror(errno));
+ return -1;
+ }
+
+ return idmap_scan(overlay_dir, target_package_name, target_apk_path, idmap_dir);
+ }
+
+ int maybe_inspect(const char *idmap_path)
+ {
+ // anyone (not just root or system) may do --inspect
+ if (!verify_file_readable(idmap_path)) {
+ ALOGD("error: failed to read idmap %s: %s\n", idmap_path, strerror(errno));
+ return -1;
+ }
+ return idmap_inspect(idmap_path);
+ }
+}
+
+int main(int argc, char **argv)
+{
+#if 0
+ {
+ char buf[1024];
+ buf[0] = '\0';
+ for (int i = 0; i < argc; ++i) {
+ strncat(buf, argv[i], sizeof(buf) - 1);
+ strncat(buf, " ", sizeof(buf) - 1);
+ }
+ ALOGD("%s:%d: uid=%d gid=%d argv=%s\n", __FILE__, __LINE__, getuid(), getgid(), buf);
+ }
+#endif
+
+ if (argc == 2 && !strcmp(argv[1], "--help")) {
+ printf("%s\n", usage);
+ return 0;
+ }
+
+ if (argc == 5 && !strcmp(argv[1], "--fd")) {
+ return maybe_create_fd(argv[2], argv[3], argv[4]);
+ }
+
+ if (argc == 5 && !strcmp(argv[1], "--path")) {
+ return maybe_create_path(argv[2], argv[3], argv[4]);
+ }
+
+ if (argc == 6 && !strcmp(argv[1], "--scan")) {
+ return maybe_scan(argv[2], argv[3], argv[4], argv[5]);
+ }
+
+ if (argc == 3 && !strcmp(argv[1], "--inspect")) {
+ return maybe_inspect(argv[2]);
+ }
+
+ fprintf(stderr, "Usage: don't use this (cf dexopt usage).\n");
+ return EXIT_FAILURE;
+}
diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h
new file mode 100644
index 0000000..f507dd8
--- /dev/null
+++ b/cmds/idmap/idmap.h
@@ -0,0 +1,34 @@
+#ifndef _IDMAP_H_
+#define _IDMAP_H_
+
+#define LOG_TAG "idmap"
+
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+#ifndef TEMP_FAILURE_RETRY
+// Used to retry syscalls that can return EINTR.
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
+
+int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path,
+ const char *idmap_path);
+
+int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd);
+
+// Regarding target_package_name: the idmap_scan implementation should
+// be able to extract this from the manifest in target_apk_path,
+// simplifying the external API.
+int idmap_scan(const char *overlay_dir, const char *target_package_name,
+ const char *target_apk_path, const char *idmap_dir);
+
+int idmap_inspect(const char *idmap_path);
+
+#endif // _IDMAP_H_
diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp
new file mode 100644
index 0000000..a59f5d3
--- /dev/null
+++ b/cmds/idmap/inspect.cpp
@@ -0,0 +1,291 @@
+#include "idmap.h"
+
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <utils/String8.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+using namespace android;
+
+#define NEXT(b, i, o) do { if (buf.next(&i, &o) < 0) { return -1; } } while (0)
+
+namespace {
+ static const uint32_t IDMAP_MAGIC = 0x706d6469;
+ static const size_t PATH_LENGTH = 256;
+ static const uint32_t IDMAP_HEADER_SIZE = (3 + 2 * (PATH_LENGTH / sizeof(uint32_t)));
+
+ void printe(const char *fmt, ...);
+
+ class IdmapBuffer {
+ private:
+ char *buf_;
+ size_t len_;
+ mutable size_t pos_;
+ public:
+ IdmapBuffer() : buf_((char *)MAP_FAILED), len_(0), pos_(0) {}
+
+ ~IdmapBuffer() {
+ if (buf_ != MAP_FAILED) {
+ munmap(buf_, len_);
+ }
+ }
+
+ int init(const char *idmap_path)
+ {
+ struct stat st;
+ int fd;
+
+ if (stat(idmap_path, &st) < 0) {
+ printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
+ return -1;
+ }
+ len_ = st.st_size;
+ if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
+ printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
+ return -1;
+ }
+ if ((buf_ = (char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+ close(fd);
+ printe("failed to mmap idmap: %s\n", strerror(errno));
+ return -1;
+ }
+ close(fd);
+ return 0;
+ }
+
+ int next(uint32_t *i, uint32_t *offset) const
+ {
+ if (!buf_) {
+ printe("failed to read next uint32_t: buffer not initialized\n");
+ return -1;
+ }
+ if (pos_ + 4 > len_) {
+ printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
+ pos_);
+ return -1;
+ }
+ *offset = pos_ / sizeof(uint32_t);
+ char a = buf_[pos_++];
+ char b = buf_[pos_++];
+ char c = buf_[pos_++];
+ char d = buf_[pos_++];
+ *i = (d << 24) | (c << 16) | (b << 8) | a;
+ return 0;
+ }
+
+ int nextPath(char *b, uint32_t *offset_start, uint32_t *offset_end) const
+ {
+ if (!buf_) {
+ printe("failed to read next path: buffer not initialized\n");
+ return -1;
+ }
+ if (pos_ + PATH_LENGTH > len_) {
+ printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
+ return -1;
+ }
+ memcpy(b, buf_ + pos_, PATH_LENGTH);
+ *offset_start = pos_ / sizeof(uint32_t);
+ pos_ += PATH_LENGTH;
+ *offset_end = pos_ / sizeof(uint32_t) - 1;
+ return 0;
+ }
+ };
+
+ void printe(const char *fmt, ...)
+ {
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "error: ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ }
+
+ void print_header()
+ {
+ printf("SECTION ENTRY VALUE OFFSET COMMENT\n");
+ }
+
+ void print(const char *section, const char *subsection, uint32_t value, uint32_t offset,
+ const char *fmt, ...)
+ {
+ va_list ap;
+
+ va_start(ap, fmt);
+ printf("%-12s %-12s 0x%08x 0x%-4x ", section, subsection, value, offset);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
+ }
+
+ void print_path(const char *section, const char *subsection, uint32_t offset_start,
+ uint32_t offset_end, const char *fmt, ...)
+ {
+ va_list ap;
+
+ va_start(ap, fmt);
+ printf("%-12s %-12s .......... 0x%02x-0x%02x ", section, subsection, offset_start,
+ offset_end);
+ vprintf(fmt, ap);
+ printf("\n");
+ va_end(ap);
+ }
+
+ int resource_metadata(const AssetManager& am, uint32_t res_id,
+ String8 *package, String8 *type, String8 *name)
+ {
+ const ResTable& rt = am.getResources();
+ struct ResTable::resource_name data;
+ if (!rt.getResourceName(res_id, false, &data)) {
+ printe("failed to get resource name id=0x%08x\n", res_id);
+ return -1;
+ }
+ if (package) {
+ *package = String8(String16(data.package, data.packageLen));
+ }
+ if (type) {
+ *type = String8(String16(data.type, data.typeLen));
+ }
+ if (name) {
+ *name = String8(String16(data.name, data.nameLen));
+ }
+ return 0;
+ }
+
+ int package_id(const AssetManager& am)
+ {
+ return (am.getResources().getBasePackageId(0)) << 24;
+ }
+
+ int parse_idmap_header(const IdmapBuffer& buf, AssetManager& am)
+ {
+ uint32_t i, o, e;
+ char path[PATH_LENGTH];
+
+ NEXT(buf, i, o);
+ if (i != IDMAP_MAGIC) {
+ printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
+ "constant 0x%08x\n", i, IDMAP_MAGIC);
+ return -1;
+ }
+ print_header();
+ print("IDMAP HEADER", "magic", i, o, "");
+
+ NEXT(buf, i, o);
+ print("", "base crc", i, o, "");
+
+ NEXT(buf, i, o);
+ print("", "overlay crc", i, o, "");
+
+ if (buf.nextPath(path, &o, &e) < 0) {
+ // printe done from IdmapBuffer::nextPath
+ return -1;
+ }
+ print_path("", "base path", o, e, "%s", path);
+ if (!am.addAssetPath(String8(path), NULL)) {
+ printe("failed to add '%s' as asset path\n", path);
+ return -1;
+ }
+
+ if (buf.nextPath(path, &o, &e) < 0) {
+ // printe done from IdmapBuffer::nextPath
+ return -1;
+ }
+ print_path("", "overlay path", o, e, "%s", path);
+
+ return 0;
+ }
+
+ int parse_data_header(const IdmapBuffer& buf, const AssetManager& am, Vector<uint32_t>& types)
+ {
+ uint32_t i, o;
+ const uint32_t numeric_package = package_id(am);
+
+ NEXT(buf, i, o);
+ print("DATA HEADER", "types count", i, o, "");
+ const uint32_t N = i;
+
+ for (uint32_t j = 0; j < N; ++j) {
+ NEXT(buf, i, o);
+ if (i == 0) {
+ print("", "padding", i, o, "");
+ } else {
+ String8 type;
+ const uint32_t numeric_type = (j + 1) << 16;
+ const uint32_t res_id = numeric_package | numeric_type;
+ if (resource_metadata(am, res_id, NULL, &type, NULL) < 0) {
+ // printe done from resource_metadata
+ return -1;
+ }
+ print("", "type offset", i, o, "absolute offset 0x%02x, %s",
+ i + IDMAP_HEADER_SIZE, type.string());
+ types.add(numeric_type);
+ }
+ }
+
+ return 0;
+ }
+
+ int parse_data_block(const IdmapBuffer& buf, const AssetManager& am, size_t numeric_type)
+ {
+ uint32_t i, o, n, id_offset;
+ const uint32_t numeric_package = package_id(am);
+
+ NEXT(buf, i, o);
+ print("DATA BLOCK", "entry count", i, o, "");
+ n = i;
+
+ NEXT(buf, i, o);
+ print("", "entry offset", i, o, "");
+ id_offset = i;
+
+ for ( ; n > 0; --n) {
+ String8 type, name;
+
+ NEXT(buf, i, o);
+ if (i == 0) {
+ print("", "padding", i, o, "");
+ } else {
+ uint32_t res_id = numeric_package | numeric_type | id_offset;
+ if (resource_metadata(am, res_id, NULL, &type, &name) < 0) {
+ // printe done from resource_metadata
+ return -1;
+ }
+ print("", "entry", i, o, "%s/%s", type.string(), name.string());
+ }
+ ++id_offset;
+ }
+
+ return 0;
+ }
+}
+
+int idmap_inspect(const char *idmap_path)
+{
+ IdmapBuffer buf;
+ if (buf.init(idmap_path) < 0) {
+ // printe done from IdmapBuffer::init
+ return EXIT_FAILURE;
+ }
+ AssetManager am;
+ if (parse_idmap_header(buf, am) < 0) {
+ // printe done from parse_idmap_header
+ return EXIT_FAILURE;
+ }
+ Vector<uint32_t> types;
+ if (parse_data_header(buf, am, types) < 0) {
+ // printe done from parse_data_header
+ return EXIT_FAILURE;
+ }
+ const size_t N = types.size();
+ for (size_t i = 0; i < N; ++i) {
+ if (parse_data_block(buf, am, types.itemAt(i)) < 0) {
+ // printe done from parse_data_block
+ return EXIT_FAILURE;
+ }
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
new file mode 100644
index 0000000..c5fc941
--- /dev/null
+++ b/cmds/idmap/scan.cpp
@@ -0,0 +1,244 @@
+#include "idmap.h"
+
+#include <UniquePtr.h>
+#include <androidfw/ResourceTypes.h>
+#include <androidfw/StreamingZipInflater.h>
+#include <androidfw/ZipFileRO.h>
+#include <private/android_filesystem_config.h> // for AID_SYSTEM
+#include <utils/SortedVector.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+
+#include <dirent.h>
+
+#define NO_OVERLAY_TAG (-1000)
+
+using namespace android;
+
+namespace {
+ struct Overlay {
+ Overlay() {}
+ Overlay(const String8& a, const String8& i, int p) :
+ apk_path(a), idmap_path(i), priority(p) {}
+
+ bool operator<(Overlay const& rhs) const
+ {
+ // Note: order is reversed by design
+ return rhs.priority < priority;
+ }
+
+ String8 apk_path;
+ String8 idmap_path;
+ int priority;
+ };
+
+ bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
+ {
+ FILE* fout = fopen(filename, "w");
+ if (fout == NULL) {
+ return false;
+ }
+
+ for (size_t i = 0; i < overlayVector.size(); ++i) {
+ const Overlay& overlay = overlayVector[i];
+ fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
+ }
+
+ fclose(fout);
+
+ // Make file world readable since Zygote (running as root) will read
+ // it when creating the initial AssetManger object
+ const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
+ if (chmod(filename, mode) == -1) {
+ unlink(filename);
+ return false;
+ }
+
+ return true;
+ }
+
+ String8 flatten_path(const char *path)
+ {
+ String16 tmp(path);
+ tmp.replaceAll('/', '@');
+ return String8(tmp);
+ }
+
+ int mkdir_p(const String8& path, uid_t uid, gid_t gid)
+ {
+ static const mode_t mode =
+ S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ struct stat st;
+
+ if (stat(path.string(), &st) == 0) {
+ return 0;
+ }
+ if (mkdir_p(path.getPathDir(), uid, gid) < 0) {
+ return -1;
+ }
+ if (mkdir(path.string(), 0755) != 0) {
+ return -1;
+ }
+ if (chown(path.string(), uid, gid) == -1) {
+ return -1;
+ }
+ if (chmod(path.string(), mode) == -1) {
+ return -1;
+ }
+ return 0;
+ }
+
+ int parse_overlay_tag(const ResXMLTree& parser, const char *target_package_name)
+ {
+ const size_t N = parser.getAttributeCount();
+ String16 target;
+ int priority = -1;
+ for (size_t i = 0; i < N; ++i) {
+ size_t len;
+ String16 key(parser.getAttributeName(i, &len));
+ if (key == String16("targetPackage")) {
+ const uint16_t *p = parser.getAttributeStringValue(i, &len);
+ if (p) {
+ target = String16(p, len);
+ }
+ } else if (key == String16("priority")) {
+ Res_value v;
+ if (parser.getAttributeValue(i, &v) == sizeof(Res_value)) {
+ priority = v.data;
+ if (priority < 0 || priority > 9999) {
+ return -1;
+ }
+ }
+ }
+ }
+ if (target == String16(target_package_name)) {
+ return priority;
+ }
+ return NO_OVERLAY_TAG;
+ }
+
+ int parse_manifest(const void *data, size_t size, const char *target_package_name)
+ {
+ ResXMLTree parser(data, size);
+ if (parser.getError() != NO_ERROR) {
+ ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
+ return -1;
+ }
+
+ ResXMLParser::event_code_t type;
+ do {
+ type = parser.next();
+ if (type == ResXMLParser::START_TAG) {
+ size_t len;
+ String16 tag(parser.getElementName(&len));
+ if (tag == String16("overlay")) {
+ return parse_overlay_tag(parser, target_package_name);
+ }
+ }
+ } while (type != ResXMLParser::BAD_DOCUMENT && type != ResXMLParser::END_DOCUMENT);
+
+ return NO_OVERLAY_TAG;
+ }
+
+ int parse_apk(const char *path, const char *target_package_name)
+ {
+ UniquePtr<ZipFileRO> zip(ZipFileRO::open(path));
+ if (zip.get() == NULL) {
+ ALOGW("%s: failed to open zip %s\n", __FUNCTION__, path);
+ return -1;
+ }
+ ZipEntryRO entry;
+ if ((entry = zip->findEntryByName("AndroidManifest.xml")) == NULL) {
+ ALOGW("%s: failed to find entry AndroidManifest.xml\n", __FUNCTION__);
+ return -1;
+ }
+ size_t uncompLen = 0;
+ int method;
+ if (!zip->getEntryInfo(entry, &method, &uncompLen, NULL, NULL, NULL, NULL)) {
+ ALOGW("%s: failed to read entry info\n", __FUNCTION__);
+ return -1;
+ }
+ if (method != ZipFileRO::kCompressDeflated) {
+ ALOGW("%s: cannot handle zip compression method %d\n", __FUNCTION__, method);
+ return -1;
+ }
+ FileMap *dataMap = zip->createEntryFileMap(entry);
+ if (!dataMap) {
+ ALOGW("%s: failed to create FileMap\n", __FUNCTION__);
+ return -1;
+ }
+ char *buf = new char[uncompLen];
+ if (NULL == buf) {
+ ALOGW("%s: failed to allocate %d byte\n", __FUNCTION__, uncompLen);
+ dataMap->release();
+ return -1;
+ }
+ StreamingZipInflater inflater(dataMap, uncompLen);
+ if (inflater.read(buf, uncompLen) < 0) {
+ ALOGW("%s: failed to inflate %d byte\n", __FUNCTION__, uncompLen);
+ delete[] buf;
+ dataMap->release();
+ return -1;
+ }
+
+ int priority = parse_manifest(buf, uncompLen, target_package_name);
+ delete[] buf;
+ dataMap->release();
+ return priority;
+ }
+}
+
+int idmap_scan(const char *overlay_dir, const char *target_package_name,
+ const char *target_apk_path, const char *idmap_dir)
+{
+ String8 filename = String8(idmap_dir);
+ filename.appendPath("overlays.list");
+ if (unlink(filename.string()) != 0 && errno != ENOENT) {
+ return EXIT_FAILURE;
+ }
+
+ DIR *dir = opendir(overlay_dir);
+ if (dir == NULL) {
+ return EXIT_FAILURE;
+ }
+
+ SortedVector<Overlay> overlayVector;
+ struct dirent *dirent;
+ while ((dirent = readdir(dir)) != NULL) {
+ struct stat st;
+ char overlay_apk_path[PATH_MAX + 1];
+ snprintf(overlay_apk_path, PATH_MAX, "%s/%s", overlay_dir, dirent->d_name);
+ if (stat(overlay_apk_path, &st) < 0) {
+ continue;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ continue;
+ }
+
+ int priority = parse_apk(overlay_apk_path, target_package_name);
+ if (priority < 0) {
+ continue;
+ }
+
+ String8 idmap_path(idmap_dir);
+ idmap_path.appendPath(flatten_path(overlay_apk_path + 1));
+ idmap_path.append("@idmap");
+
+ if (idmap_create_path(target_apk_path, overlay_apk_path, idmap_path.string()) != 0) {
+ ALOGE("error: failed to create idmap for target=%s overlay=%s idmap=%s\n",
+ target_apk_path, overlay_apk_path, idmap_path.string());
+ continue;
+ }
+
+ Overlay overlay(String8(overlay_apk_path), idmap_path, priority);
+ overlayVector.add(overlay);
+ }
+
+ closedir(dir);
+
+ if (!writePackagesList(filename.string(), overlayVector)) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index d1ded10..9ad2e76 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -39,6 +39,7 @@
import android.content.res.Resources;
import android.net.Uri;
import android.os.IUserManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -1011,6 +1012,27 @@
public void runCreateUser() {
String name;
+ int relatedUserId = -1;
+ int flags = 0;
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if ("--relatedTo".equals(opt)) {
+ String optionData = nextOptionData();
+ if (optionData == null || !isNumber(optionData)) {
+ System.err.println("Error: no USER_ID specified");
+ showUsage();
+ return;
+ } else {
+ relatedUserId = Integer.parseInt(optionData);
+ }
+ } else if ("--managed".equals(opt)) {
+ flags |= UserInfo.FLAG_MANAGED_PROFILE;
+ } else {
+ System.err.println("Error: unknown option " + opt);
+ showUsage();
+ return;
+ }
+ }
String arg = nextArg();
if (arg == null) {
System.err.println("Error: no user name specified.");
@@ -1018,7 +1040,16 @@
}
name = arg;
try {
- final UserInfo info = mUm.createUser(name, 0);
+ UserInfo info = null;
+ if (relatedUserId < 0) {
+ info = mUm.createUser(name, flags);
+ } else {
+ if (Process.myUid() != 0) {
+ System.err.println("Error: not running as root.");
+ return;
+ }
+ info = mUm.createRelatedUser(name, flags, relatedUserId);
+ }
if (info != null) {
System.out.println("Success: created user id " + info.id);
} else {
@@ -1530,7 +1561,7 @@
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
System.err.println(" pm trim-caches DESIRED_FREE_SPACE");
- System.err.println(" pm create-user USER_NAME");
+ System.err.println(" pm create-user [--relatedTo USER_ID] [--managed] USER_NAME");
System.err.println(" pm remove-user USER_ID");
System.err.println(" pm get-max-users");
System.err.println("");
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index a57de01..2efe4d3 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -141,7 +141,7 @@
ScreenshotClient screenshot;
sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
- if (display != NULL && screenshot.update(display) == NO_ERROR) {
+ if (display != NULL && screenshot.update(display, false) == NO_ERROR) {
base = screenshot.getPixels();
w = screenshot.getWidth();
h = screenshot.getHeight();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a8716bf..4f0683c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -824,7 +824,7 @@
}
/**
- * Return the LoaderManager for this fragment, creating it if needed.
+ * Return the LoaderManager for this activity, creating it if needed.
*/
public LoaderManager getLoaderManager() {
if (mLoaderManager != null) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5239cc6..3258585 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1550,11 +1550,11 @@
/**
* Creates the top level resources for the given package.
*/
- Resources getTopLevelResources(String resDir,
+ Resources getTopLevelResources(String resDir, String[] overlayDirs,
int displayId, Configuration overrideConfiguration,
LoadedApk pkgInfo) {
- return mResourcesManager.getTopLevelResources(resDir, displayId, overrideConfiguration,
- pkgInfo.getCompatibilityInfo(), null);
+ return mResourcesManager.getTopLevelResources(resDir, overlayDirs, displayId,
+ overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
}
final Handler getHandler() {
@@ -3949,6 +3949,7 @@
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
// Cleanup hardware accelerated stuff
+ // TODO: Do we actually want to do this in response to all config changes?
WindowManagerGlobal.getInstance().trimLocalMemory();
freeTextLayoutCachesIfNeeded(configDiff);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 48ec420..14f0829 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -39,6 +39,7 @@
public class ActivityView extends ViewGroup {
private final String TAG = "ActivityView";
+ private final boolean DEBUG = false;
private final TextureView mTextureView;
private IActivityContainer mActivityContainer;
@@ -76,6 +77,7 @@
mTextureView = new TextureView(context);
mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener());
addView(mTextureView);
+ if (DEBUG) Log.v(TAG, "ctor()");
}
@Override
@@ -85,6 +87,8 @@
@Override
protected void onAttachedToWindow() {
+ if (DEBUG) Log.v(TAG, "onAttachedToWindow()");
+ super.onAttachedToWindow();
try {
final IBinder token = mActivity.getActivityToken();
mActivityContainer =
@@ -99,6 +103,8 @@
@Override
protected void onDetachedFromWindow() {
+ if (DEBUG) Log.v(TAG, "onDetachedFromWindow(): mActivityContainer=" + mActivityContainer);
+ super.onDetachedFromWindow();
if (mActivityContainer != null) {
detach();
mActivityContainer = null;
@@ -107,11 +113,17 @@
@Override
protected void onWindowVisibilityChanged(int visibility) {
+ if (DEBUG) Log.v(TAG, "onWindowVisibilityChanged(): visibility=" + visibility);
super.onWindowVisibilityChanged(visibility);
- if (visibility == View.VISIBLE) {
- attachToSurfaceWhenReady();
- } else {
- detach();
+ switch (visibility) {
+ case View.VISIBLE:
+ attachToSurfaceWhenReady();
+ break;
+ case View.INVISIBLE:
+ break;
+ case View.GONE:
+ detach();
+ break;
}
}
@@ -143,6 +155,8 @@
}
public void startActivity(Intent intent) {
+ if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " +
+ (isAttachedToDisplay() ? "" : "not") + " attached");
if (mSurface != null) {
try {
mActivityContainer.startActivity(intent);
@@ -165,6 +179,8 @@
}
public void startActivity(IntentSender intentSender) {
+ if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " +
+ (isAttachedToDisplay() ? "" : "not") + " attached");
final IIntentSender iIntentSender = intentSender.getTarget();
if (mSurface != null) {
startActivityIntentSender(iIntentSender);
@@ -175,6 +191,8 @@
}
public void startActivity(PendingIntent pendingIntent) {
+ if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " "
+ + (isAttachedToDisplay() ? "" : "not") + " attached");
final IIntentSender iIntentSender = pendingIntent.getTarget();
if (mSurface != null) {
startActivityIntentSender(iIntentSender);
@@ -205,6 +223,8 @@
"ActivityView: Unable to create ActivityContainer. " + e);
}
+ if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null ||
+ mQueuedPendingIntent != null ? "" : "no") + " queued intent");
if (mQueuedIntent != null) {
startActivity(mQueuedIntent);
mQueuedIntent = null;
@@ -215,6 +235,7 @@
}
private void detach() {
+ if (DEBUG) Log.d(TAG, "detach: attached=" + isAttachedToDisplay());
if (mSurface != null) {
try {
mActivityContainer.detachFromDisplay();
@@ -229,6 +250,8 @@
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
int height) {
+ if (DEBUG) Log.d(TAG, "onSurfaceTextureAvailable: width=" + width + " height="
+ + height);
mWidth = width;
mHeight = height;
if (mActivityContainer != null) {
@@ -239,12 +262,12 @@
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
int height) {
- Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height);
+ if (DEBUG) Log.d(TAG, "onSurfaceTextureSizeChanged: w=" + width + " h=" + height);
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
- Log.d(TAG, "onSurfaceTextureDestroyed");
+ if (DEBUG) Log.d(TAG, "onSurfaceTextureDestroyed");
detach();
return true;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b910ba5..6b48130 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -772,7 +772,7 @@
}
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
- Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
+ app.resourceDirs, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
if (r != null) {
return r;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 190ddb4..7efb3f1 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -17,6 +17,7 @@
package android.app;
import android.os.Build;
+
import com.android.internal.policy.PolicyManager;
import com.android.internal.util.Preconditions;
@@ -62,6 +63,7 @@
import android.location.LocationManager;
import android.media.AudioManager;
import android.media.MediaRouter;
+import android.media.MediaSessionManager;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.INetworkPolicyManager;
@@ -356,10 +358,11 @@
ctx.mMainThread.getHandler());
}});
- registerService(CONNECTIVITY_SERVICE, new StaticServiceFetcher() {
- public Object createStaticService() {
+ registerService(CONNECTIVITY_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(CONNECTIVITY_SERVICE);
- return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b));
+ return new ConnectivityManager(IConnectivityManager.Stub.asInterface(b),
+ ctx.getPackageName());
}});
registerService(COUNTRY_DETECTOR, new StaticServiceFetcher() {
@@ -587,6 +590,12 @@
public Object createService(ContextImpl ctx) {
return new ConsumerIrManager(ctx);
}});
+
+ registerService(MEDIA_SESSION_SERVICE, new ServiceFetcher() {
+ public Object createService(ContextImpl ctx) {
+ return new MediaSessionManager(ctx);
+ }
+ });
}
static ContextImpl getImpl(Context context) {
@@ -1911,8 +1920,8 @@
ContextImpl c = new ContextImpl();
c.init(mPackageInfo, null, mMainThread);
c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
- getDisplayId(), overrideConfiguration, mResources.getCompatibilityInfo(),
- mActivityToken);
+ mPackageInfo.getOverlayDirs(), getDisplayId(), overrideConfiguration,
+ mResources.getCompatibilityInfo(), mActivityToken);
return c;
}
@@ -1929,7 +1938,7 @@
context.mDisplay = display;
DisplayAdjustments daj = getDisplayAdjustments(displayId);
context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
- displayId, null, daj.getCompatibilityInfo(), null);
+ mPackageInfo.getOverlayDirs(), displayId, null, daj.getCompatibilityInfo(), null);
return context;
}
@@ -2041,7 +2050,8 @@
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
mDisplayAdjustments.setActivityToken(activityToken);
mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
- Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
+ mPackageInfo.getOverlayDirs(), Display.DEFAULT_DISPLAY, null, compatInfo,
+ activityToken);
} else {
mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
mDisplayAdjustments.setActivityToken(activityToken);
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 8476609..ef9f26e 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -28,7 +28,7 @@
/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
void set(int type, long triggerAtTime, long windowLength,
long interval, in PendingIntent operation, in WorkSource workSource);
- void setTime(long millis);
+ boolean setTime(long millis);
void setTimeZone(String zone);
void remove(in PendingIntent operation);
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 4239a5d..0115d1b 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -76,6 +76,7 @@
final String mPackageName;
private final String mAppDir;
private final String mResDir;
+ private final String[] mOverlayDirs;
private final String[] mSharedLibraries;
private final String mDataDir;
private final String mLibDir;
@@ -120,6 +121,7 @@
final int myUid = Process.myUid();
mResDir = aInfo.uid == myUid ? aInfo.sourceDir
: aInfo.publicSourceDir;
+ mOverlayDirs = aInfo.resourceDirs;
if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
mPackageName);
@@ -159,6 +161,7 @@
mPackageName = name;
mAppDir = null;
mResDir = null;
+ mOverlayDirs = null;
mSharedLibraries = null;
mDataDir = null;
mDataDirFile = null;
@@ -471,6 +474,10 @@
return mResDir;
}
+ public String[] getOverlayDirs() {
+ return mOverlayDirs;
+ }
+
public String getDataDir() {
return mDataDir;
}
@@ -485,7 +492,7 @@
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir,
+ mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs,
Display.DEFAULT_DISPLAY, null, this);
}
return mResources;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index d3b0763..d4de112 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -231,7 +231,7 @@
* <p class="note">For security reasons, the {@link android.content.Intent}
* you supply here should almost always be an <em>explicit intent</em>,
* that is specify an explicit component to be delivered to through
- * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+ * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should start
* the activity.
@@ -262,7 +262,7 @@
* <p class="note">For security reasons, the {@link android.content.Intent}
* you supply here should almost always be an <em>explicit intent</em>,
* that is specify an explicit component to be delivered to through
- * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+ * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should start
* the activity.
@@ -354,7 +354,7 @@
* <p class="note">For security reasons, the {@link android.content.Intent} objects
* you supply here should almost always be <em>explicit intents</em>,
* that is specify an explicit component to be delivered to through
- * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+ * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should start
* the activity.
@@ -404,7 +404,7 @@
* <p class="note">For security reasons, the {@link android.content.Intent} objects
* you supply here should almost always be <em>explicit intents</em>,
* that is specify an explicit component to be delivered to through
- * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+ * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should start
* the activity.
@@ -474,7 +474,7 @@
* <p class="note">For security reasons, the {@link android.content.Intent}
* you supply here should almost always be an <em>explicit intent</em>,
* that is specify an explicit component to be delivered to through
- * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+ * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should perform
* the broadcast.
@@ -528,7 +528,7 @@
* <p class="note">For security reasons, the {@link android.content.Intent}
* you supply here should almost always be an <em>explicit intent</em>,
* that is specify an explicit component to be delivered to through
- * {@link Intent#setClass(android.content.Context, Class)} Intent.setClass</p>
+ * {@link Intent#setClass(android.content.Context, Class) Intent.setClass}</p>
*
* @param context The Context in which this PendingIntent should start
* the service.
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index f55dba4..728f372 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -147,7 +147,7 @@
* @param compatInfo the compability info. Must not be null.
* @param token the application token for determining stack bounds.
*/
- public Resources getTopLevelResources(String resDir, int displayId,
+ public Resources getTopLevelResources(String resDir, String[] overlayDirs, int displayId,
Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
final float scale = compatInfo.applicationScale;
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
@@ -180,6 +180,12 @@
return null;
}
+ if (overlayDirs != null) {
+ for (String idmapPath : overlayDirs) {
+ assets.addOverlayPath(idmapPath);
+ }
+ }
+
//Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics dm = getDisplayMetricsLocked(displayId);
Configuration config;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 40bdb73..b4488cd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -22,6 +22,7 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -1690,16 +1691,16 @@
* user. Also, this method must be called before the user has been used for the first time.
* @param packageName the package name of the application to be registered as profile owner.
* @param ownerName the human readable name of the organisation associated with this DPM.
+ * @param userHandle the userId to set the profile owner for.
* @return whether the package was successfully registered as the profile owner.
* @throws IllegalArgumentException if packageName is null, the package isn't installed, or
* the user has already been set up.
*/
- public boolean setProfileOwner(String packageName, String ownerName)
+ public boolean setProfileOwner(String packageName, String ownerName, int userHandle)
throws IllegalArgumentException {
if (mService != null) {
try {
- return mService.setProfileOwner(packageName, ownerName,
- Process.myUserHandle().getIdentifier());
+ return mService.setProfileOwner(packageName, ownerName, userHandle);
} catch (RemoteException re) {
Log.w(TAG, "Failed to set profile owner", re);
throw new IllegalArgumentException("Couldn't set profile owner.", re);
@@ -1766,4 +1767,53 @@
}
return null;
}
+
+ /**
+ * Called by a profile owner or device owner to add a default intent handler activity for
+ * intents that match a certain intent filter. This activity will remain the default intent
+ * handler even if the set of potential event handlers for the intent filter changes and if
+ * the intent preferences are reset.
+ *
+ * <p>The default disambiguation mechanism takes over if the activity is not installed
+ * (anymore). When the activity is (re)installed, it is automatically reset as default
+ * intent handler for the filter.
+ *
+ * <p>The calling device admin must be a profile owner or device owner. If it is not, a
+ * security exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param filter The IntentFilter for which a default handler is added.
+ * @param activity The Activity that is added as default intent handler.
+ */
+ public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter,
+ ComponentName activity) {
+ if (mService != null) {
+ try {
+ mService.addPersistentPreferredActivity(admin, filter, activity);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
+
+ /**
+ * Called by a profile owner or device owner to remove all persistent intent handler preferences
+ * associated with the given package that were set by {@link #addPersistentPreferredActivity}.
+ *
+ * <p>The calling device admin must be a profile owner. If it is not, a security
+ * exception will be thrown.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The name of the package for which preferences are removed.
+ */
+ public void clearPackagePersistentPreferredActivities(ComponentName admin,
+ String packageName) {
+ if (mService != null) {
+ try {
+ mService.clearPackagePersistentPreferredActivities(admin, packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 9d189db..8119585 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -18,6 +18,7 @@
package android.app.admin;
import android.content.ComponentName;
+import android.content.IntentFilter;
import android.os.RemoteCallback;
/**
@@ -109,4 +110,7 @@
boolean installCaCert(in byte[] certBuffer);
void uninstallCaCert(in byte[] certBuffer);
+
+ void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity);
+ void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 3fc933d..8694416 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -192,6 +192,14 @@
*/
public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
+ /**
+ * This is the Android platform's generic MIME type to match any MIME
+ * type of the form "{@link #CURSOR_ITEM_BASE_TYPE}/{@code SUB_TYPE}".
+ * {@code SUB_TYPE} is the sub-type of the application-dependent
+ * content, e.g., "audio", "video", "playlist".
+ */
+ public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
+
/** @hide */
public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
/** @hide */
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 9f90de0..d05d1a1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1840,7 +1840,7 @@
* @hide like {@link #stopService(Intent)} but for a specific user.
*/
public abstract boolean stopServiceAsUser(Intent service, UserHandle user);
-
+
/**
* Connect to an application service, creating it if needed. This defines
* a dependency between your application and the service. The given
@@ -1989,7 +1989,8 @@
USER_SERVICE,
//@hide: APP_OPS_SERVICE
CAMERA_SERVICE,
- PRINT_SERVICE
+ PRINT_SERVICE,
+ MEDIA_SESSION_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -2351,6 +2352,15 @@
/**
* Use with {@link #getSystemService} to retrieve a
+ * {@link android.media.MediaSessionManager} for managing media Sessions.
+ *
+ * @see #getSystemService
+ * @see android.media.MediaSessionManager
+ */
+ public static final String MEDIA_SESSION_SERVICE = "media_session";
+
+ /**
+ * Use with {@link #getSystemService} to retrieve a
* {@link android.telephony.TelephonyManager} for handling management the
* telephony features of the device.
*
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index f3828b0..e9d82af 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -24,7 +24,7 @@
import java.io.PrintWriter;
/**
- * An abstract class that performs asynchronous loading of data. While Loaders are active
+ * A class that performs asynchronous loading of data. While Loaders are active
* they should monitor the source of their data and deliver new results when the contents
* change. See {@link android.app.LoaderManager} for more detail.
*
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 20002ad..c9fb530 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -237,6 +237,10 @@
int getPreferredActivities(out List<IntentFilter> outFilters,
out List<ComponentName> outActivities, String packageName);
+ void addPersistentPreferredActivity(in IntentFilter filter, in ComponentName activity, int userId);
+
+ void clearPackagePersistentPreferredActivities(String packageName, int userId);
+
/**
* Report the set of 'Home' activity candidates, plus (if any) which of them
* is the current "always use this one" setting.
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index af1a6d5..ef0c4d5 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -209,6 +209,19 @@
*/
public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
/**
+ * Flag for {@link #requiredForProfile}
+ * The application will always be installed for a restricted profile.
+ * @hide
+ */
+ public static final int RESTRICTED_PROFILE = 1;
+ /**
+ * Flag for {@link #requiredForProfile}
+ * The application will always be installed for a managed profile.
+ * @hide
+ */
+ public static final int MANAGED_PROFILE = 2;
+
+ /**
* The install location requested by the activity. From the
* {@link android.R.attr#installLocation} attribute, one of
* {@link #INSTALL_LOCATION_AUTO},
@@ -218,6 +231,12 @@
*/
public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
+ /**
+ * Defines which profiles this app is required for.
+ * @hide
+ */
+ public int requiredForProfile;
+
/** @hide */
public boolean requiredForAllUsers;
@@ -227,6 +246,14 @@
/** @hide */
public String requiredAccountType;
+ /**
+ * What package, if any, this package will overlay.
+ *
+ * Package name of target package, or null.
+ * @hide
+ */
+ public String overlayTarget;
+
public PackageInfo() {
}
@@ -268,8 +295,10 @@
dest.writeTypedArray(reqFeatures, parcelableFlags);
dest.writeInt(installLocation);
dest.writeInt(requiredForAllUsers ? 1 : 0);
+ dest.writeInt(requiredForProfile);
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
+ dest.writeString(overlayTarget);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -309,7 +338,9 @@
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
installLocation = source.readInt();
requiredForAllUsers = source.readInt() != 0;
+ requiredForProfile = source.readInt();
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
+ overlayTarget = source.readString();
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0192a30..b648930 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1257,6 +1257,29 @@
public static final String FEATURE_TELEVISION = "android.hardware.type.television";
/**
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: This is a device dedicated to showing UI
+ * on a watch. A watch here is defined to be a device worn on the body, perhaps on
+ * the wrist. The user is very close when interacting with the device.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_WATCH = "android.hardware.type.watch";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports printing.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_PRINTING = "android.software.print";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device can perform backup and restore operations on installed applications.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_BACKUP = "android.software.backup";
+
+ /**
* Action to external storage service to clean out removed apps.
* @hide
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 8a1fcd3..c222003 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -304,9 +304,11 @@
if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0
|| (pi.applicationInfo.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
pi.requiredForAllUsers = p.mRequiredForAllUsers;
+ pi.requiredForProfile = p.mRequiredForProfile;
}
pi.restrictedAccountType = p.mRestrictedAccountType;
pi.requiredAccountType = p.mRequiredAccountType;
+ pi.overlayTarget = p.mOverlayTarget;
pi.firstInstallTime = firstInstallTime;
pi.lastUpdateTime = lastUpdateTime;
if ((flags&PackageManager.GET_GIDS) != 0) {
@@ -490,6 +492,11 @@
public Package parsePackage(File sourceFile, String destCodePath,
DisplayMetrics metrics, int flags) {
+ return parsePackage(sourceFile, destCodePath, metrics, flags, false);
+ }
+
+ public Package parsePackage(File sourceFile, String destCodePath,
+ DisplayMetrics metrics, int flags, boolean trustedOverlay) {
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = sourceFile.getPath();
@@ -542,7 +549,7 @@
Exception errorException = null;
try {
// XXXX todo: need to figure out correct configuration.
- pkg = parsePackage(res, parser, flags, errorText);
+ pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
@@ -951,8 +958,8 @@
}
private Package parsePackage(
- Resources res, XmlResourceParser parser, int flags, String[] outError)
- throws XmlPullParserException, IOException {
+ Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
+ String[] outError) throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
@@ -1051,6 +1058,31 @@
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
+ } else if (tagName.equals("overlay")) {
+ pkg.mTrustedOverlay = trustedOverlay;
+
+ sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay);
+ pkg.mOverlayTarget = sa.getString(
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
+ pkg.mOverlayPriority = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
+ -1);
+ sa.recycle();
+
+ if (pkg.mOverlayTarget == null) {
+ outError[0] = "<overlay> does not specify a target package";
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return null;
+ }
+ if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
+ outError[0] = "<overlay> priority must be between 0 and 9999";
+ mParseError =
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return null;
+ }
+ XmlUtils.skipCurrentTag(parser);
+
} else if (tagName.equals("keys")) {
if (!parseKeys(pkg, res, parser, attrs, outError)) {
return null;
@@ -1947,6 +1979,8 @@
false)) {
owner.mRequiredForAllUsers = true;
}
+ owner.mRequiredForProfile = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestApplication_requiredForProfile, 0);
String restrictedAccountType = sa.getString(com.android.internal.R.styleable
.AndroidManifestApplication_restrictedAccountType);
@@ -3534,6 +3568,9 @@
/* An app that's required for all users and cannot be uninstalled for a user */
public boolean mRequiredForAllUsers;
+ /* For which types of profile this app is required */
+ public int mRequiredForProfile;
+
/* The restricted account authenticator type that is used by this application */
public String mRestrictedAccountType;
@@ -3546,6 +3583,10 @@
*/
public ManifestDigest manifestDigest;
+ public String mOverlayTarget;
+ public int mOverlayPriority;
+ public boolean mTrustedOverlay;
+
/**
* Data used to feed the KeySetManager
*/
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index aa4a243..6f1d4f8 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
import android.os.UserHandle;
/**
@@ -116,6 +117,14 @@
return (flags & FLAG_MANAGED_PROFILE) == FLAG_MANAGED_PROFILE;
}
+ /**
+ * @return true if this user can be switched to.
+ **/
+ public boolean supportsSwitchTo() {
+ // TODO remove fw.show_hidden_users when we have finished developing managed profiles.
+ return !isManagedProfile() || SystemProperties.getBoolean("fw.show_hidden_users", false);
+ }
+
public UserInfo() {
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 276e19b..352825f 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -89,7 +89,7 @@
mNumRefs = 0;
incRefsLocked(this.hashCode());
}
- init();
+ init(false);
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
ensureSystemAssets();
}
@@ -112,7 +112,7 @@
incRefsLocked(this.hashCode());
}
}
- init();
+ init(true);
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
}
@@ -617,6 +617,16 @@
private native final int addAssetPathNative(String path);
+ /**
+ * Add a set of assets to overlay an already added set of assets.
+ *
+ * This is only intended for application resources. System wide resources
+ * are handled before any Java code is executed.
+ *
+ * {@hide}
+ */
+ public native final int addOverlayPath(String idmapPath);
+
/**
* Add multiple sets of assets to the asset manager at once. See
* {@link #addAssetPath(String)} for more information. Returns array of
@@ -754,7 +764,7 @@
private native final int[] getArrayStringInfo(int arrayRes);
/*package*/ native final int[] getArrayIntResource(int arrayRes);
- private native final void init();
+ private native final void init(boolean isSystem);
private native final void destroy();
private final void incRefsLocked(long id) {
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 431226a..2893522 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -17,12 +17,14 @@
package android.content.res;
import android.graphics.Color;
+
import com.android.internal.util.ArrayUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.util.SparseArray;
import android.util.StateSet;
import android.util.Xml;
@@ -172,7 +174,7 @@
* Fill in this object based on the contents of an XML "selector" element.
*/
private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
- throws XmlPullParserException, IOException {
+ throws XmlPullParserException, IOException {
int type;
@@ -195,6 +197,8 @@
continue;
}
+ int alphaRes = 0;
+ float alpha = 1.0f;
int colorRes = 0;
int color = 0xffff0000;
boolean haveColor = false;
@@ -206,17 +210,20 @@
for (i = 0; i < numAttrs; i++) {
final int stateResId = attrs.getAttributeNameResource(i);
if (stateResId == 0) break;
- if (stateResId == com.android.internal.R.attr.color) {
+ if (stateResId == com.android.internal.R.attr.alpha) {
+ alphaRes = attrs.getAttributeResourceValue(i, 0);
+ if (alphaRes == 0) {
+ alpha = attrs.getAttributeFloatValue(i, 1.0f);
+ }
+ } else if (stateResId == com.android.internal.R.attr.color) {
colorRes = attrs.getAttributeResourceValue(i, 0);
-
if (colorRes == 0) {
color = attrs.getAttributeIntValue(i, color);
haveColor = true;
}
} else {
stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
- ? stateResId
- : -stateResId;
+ ? stateResId : -stateResId;
}
}
stateSpec = StateSet.trimStateSet(stateSpec, j);
@@ -229,10 +236,18 @@
+ ": <item> tag requires a 'android:color' attribute.");
}
+ if (alphaRes != 0) {
+ alpha = r.getFraction(alphaRes, 1, 1);
+ }
+
+ // Apply alpha modulation.
+ final int alphaMod = MathUtils.constrain((int) (Color.alpha(color) * alpha), 0, 255);
+ color = (color & 0xFFFFFF) | (alphaMod << 24);
+
if (listSize == 0 || stateSpec.length == 0) {
mDefaultColor = color;
}
-
+
if (listSize + 1 >= listAllocated) {
listAllocated = ArrayUtils.idealIntArraySize(listSize + 1);
@@ -300,6 +315,7 @@
return mDefaultColor;
}
+ @Override
public String toString() {
return "ColorStateList{" +
"mStateSpecs=" + Arrays.deepToString(mStateSpecs) +
@@ -307,14 +323,16 @@
"mDefaultColor=" + mDefaultColor + '}';
}
+ @Override
public int describeContents() {
return 0;
}
+ @Override
public void writeToParcel(Parcel dest, int flags) {
final int N = mStateSpecs.length;
dest.writeInt(N);
- for (int i=0; i<N; i++) {
+ for (int i = 0; i < N; i++) {
dest.writeIntArray(mStateSpecs[i]);
}
dest.writeIntArray(mColors);
@@ -322,17 +340,19 @@
public static final Parcelable.Creator<ColorStateList> CREATOR =
new Parcelable.Creator<ColorStateList>() {
+ @Override
public ColorStateList[] newArray(int size) {
return new ColorStateList[size];
}
+ @Override
public ColorStateList createFromParcel(Parcel source) {
final int N = source.readInt();
- int[][] stateSpecs = new int[N][];
- for (int i=0; i<N; i++) {
+ final int[][] stateSpecs = new int[N][];
+ for (int i = 0; i < N; i++) {
stateSpecs[i] = source.createIntArray();
}
- int[] colors = source.createIntArray();
+ final int[] colors = source.createIntArray();
return new ColorStateList(stateSpecs, colors);
}
};
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index de00f71..da6ae56 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1625,7 +1625,7 @@
String locale = null;
if (mConfiguration.locale != null) {
- locale = mConfiguration.locale.toLanguageTag();
+ locale = localeToLanguageTag(mConfiguration.locale);
}
int width, height;
if (mMetrics.widthPixels >= mMetrics.heightPixels) {
@@ -1706,6 +1706,12 @@
}
}
+ // Locale.toLanguageTag() is not available in Java6. LayoutLib overrides
+ // this method to enable users to use Java6.
+ private String localeToLanguageTag(Locale locale) {
+ return locale.toLanguageTag();
+ }
+
/**
* Update the system resources configuration if they have previously
* been initialized.
diff --git a/core/java/android/debug/JNITest.java b/core/java/android/debug/JNITest.java
deleted file mode 100644
index 2ce374a..0000000
--- a/core/java/android/debug/JNITest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2006 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.debug;
-
-/**
- * Simple JNI verification test.
- */
-public class JNITest {
-
- public JNITest() {
- }
-
- public int test(int intArg, double doubleArg, String stringArg) {
- int[] intArray = { 42, 53, 65, 127 };
-
- return part1(intArg, doubleArg, stringArg, intArray);
- }
-
- private native int part1(int intArg, double doubleArg, String stringArg,
- int[] arrayArg);
-
- private int part2(double doubleArg, int fromArray, String stringArg) {
- int result;
-
- System.out.println(stringArg + " : " + (float) doubleArg + " : " +
- fromArray);
- result = part3(stringArg);
-
- return result + 6;
- }
-
- private static native int part3(String stringArg);
-}
-
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index f06ffaa..d27485b 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -969,6 +969,23 @@
new Key<android.hardware.camera2.Size>("android.sensor.info.pixelArraySize", android.hardware.camera2.Size.class);
/**
+ * <p>Maximum raw value output by sensor.</p>
+ * <p>This specifies the fully-saturated encoding level for the raw
+ * sample values from the sensor. This is typically caused by the
+ * sensor becoming highly non-linear or clipping. The minimum for
+ * each channel is specified by the offset in the
+ * {@link CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN android.sensor.blackLevelPattern} tag.</p>
+ * <p>The white level is typically determined either by sensor bit depth
+ * (10-14 bits is expected), or by the point where the sensor response
+ * becomes too non-linear to be useful. The default value for this is
+ * maximum representable value for a 16-bit raw sample (2^16 - 1).</p>
+ *
+ * @see CameraCharacteristics#SENSOR_BLACK_LEVEL_PATTERN
+ */
+ public static final Key<Integer> SENSOR_INFO_WHITE_LEVEL =
+ new Key<Integer>("android.sensor.info.whiteLevel", int.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>
@@ -985,10 +1002,13 @@
* <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
- * channels in the camera sensor.</p>
+ * channels in the camera sensor. The maximal value output by the
+ * sensor is represented by the value in {@link CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL android.sensor.info.whiteLevel}.</p>
* <p>The values are given in row-column scan order, with the first value
* corresponding to the element of the CFA in row=0, column=0.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ *
+ * @see CameraCharacteristics#SENSOR_INFO_WHITE_LEVEL
*/
public static final Key<int[]> SENSOR_BLACK_LEVEL_PATTERN =
new Key<int[]>("android.sensor.blackLevelPattern", int[].class);
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 42880af..2c53f03 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -92,7 +92,6 @@
* AE/AWB/AF should be on auto mode.
*
* @see #createCaptureRequest
- * @hide
*/
public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5;
@@ -105,7 +104,6 @@
* application depending on the intended use case.
*
* @see #createCaptureRequest
- * @hide
*/
public static final int TEMPLATE_MANUAL = 6;
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index a581982..ff12d77 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -999,7 +999,7 @@
/**
* <p>Use specific scene mode. Enabling this disables
* control.aeMode, control.awbMode and control.afMode
- * controls; the HAL must ignore those settings while
+ * controls; the camera device will ignore those settings while
* USE_SCENE_MODE is active (except for FACE_PRIORITY
* scene mode). Other control entries are still active.
* This setting can only be used if availableSceneModes !=
@@ -1468,14 +1468,16 @@
/**
* <p>AE is off or recently reset. When a camera device is opened, it starts in
- * this state.</p>
+ * this state. This is a transient state, the camera device may skip reporting
+ * this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_INACTIVE = 0;
/**
* <p>AE doesn't yet have a good set of control values
- * for the current scene.</p>
+ * for the current scene. This is a transient state, the camera device may skip
+ * reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AE_STATE
*/
public static final int CONTROL_AE_STATE_SEARCHING = 1;
@@ -1506,7 +1508,8 @@
* (through the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} START),
* and is currently executing it. Once PRECAPTURE
* completes, AE will transition to CONVERGED or
- * FLASH_REQUIRED as appropriate.</p>
+ * FLASH_REQUIRED as appropriate. This is a transient state, the
+ * camera device may skip reporting this state in capture result.</p>
*
* @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
* @see CaptureResult#CONTROL_AE_STATE
@@ -1520,7 +1523,8 @@
/**
* <p>AF off or has not yet tried to scan/been asked
* to scan. When a camera device is opened, it starts in
- * this state.</p>
+ * this state. This is a transient state, the camera device may
+ * skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_INACTIVE = 0;
@@ -1528,7 +1532,8 @@
/**
* <p>if CONTINUOUS_* modes are supported. AF is
* currently doing an AF scan initiated by a continuous
- * autofocus mode</p>
+ * autofocus mode. This is a transient state, the camera device may
+ * skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_SCAN = 1;
@@ -1536,15 +1541,17 @@
/**
* <p>if CONTINUOUS_* modes are supported. AF currently
* believes it is in focus, but may restart scanning at
- * any time.</p>
+ * any time. This is a transient state, the camera device may skip
+ * reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_FOCUSED = 2;
/**
* <p>if AUTO or MACRO modes are supported. AF is doing
- * an AF scan because it was triggered by AF
- * trigger</p>
+ * an AF scan because it was triggered by AF trigger. This is a
+ * transient state, the camera device may skip reporting
+ * this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3;
@@ -1552,7 +1559,7 @@
/**
* <p>if any AF mode besides OFF is supported. AF
* believes it is focused correctly and is
- * locked</p>
+ * locked.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4;
@@ -1560,7 +1567,7 @@
/**
* <p>if any AF mode besides OFF is supported. AF has
* failed to focus successfully and is
- * locked</p>
+ * locked.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_NOT_FOCUSED_LOCKED = 5;
@@ -1568,7 +1575,8 @@
/**
* <p>if CONTINUOUS_* modes are supported. AF finished a
* passive scan without finding focus, and may restart
- * scanning at any time.</p>
+ * scanning at any time. This is a transient state, the camera
+ * device may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AF_STATE
*/
public static final int CONTROL_AF_STATE_PASSIVE_UNFOCUSED = 6;
@@ -1579,14 +1587,16 @@
/**
* <p>AWB is not in auto mode. When a camera device is opened, it
- * starts in this state.</p>
+ * starts in this state. This is a transient state, the camera device may
+ * skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_INACTIVE = 0;
/**
* <p>AWB doesn't yet have a good set of control
- * values for the current scene.</p>
+ * values for the current scene. This is a transient state, the camera device
+ * may skip reporting this state in capture result.</p>
* @see CaptureResult#CONTROL_AWB_STATE
*/
public static final int CONTROL_AWB_STATE_SEARCHING = 1;
@@ -1670,6 +1680,110 @@
public static final int LENS_STATE_MOVING = 1;
//
+ // Enumeration values for CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ //
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT = 1;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_FLUORESCENT = 2;
+
+ /**
+ * <p>Incandescent light</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_TUNGSTEN = 3;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_FLASH = 4;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_FINE_WEATHER = 9;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_CLOUDY_WEATHER = 10;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_SHADE = 11;
+
+ /**
+ * <p>D 5700 - 7100K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT_FLUORESCENT = 12;
+
+ /**
+ * <p>N 4600 - 5400K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_DAY_WHITE_FLUORESCENT = 13;
+
+ /**
+ * <p>W 3900 - 4500K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_COOL_WHITE_FLUORESCENT = 14;
+
+ /**
+ * <p>WW 3200 - 3700K</p>
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_WHITE_FLUORESCENT = 15;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_A = 17;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_B = 18;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_STANDARD_C = 19;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D55 = 20;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D65 = 21;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D75 = 22;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_D50 = 23;
+
+ /**
+ * @see CaptureResult#SENSOR_REFERENCE_ILLUMINANT
+ */
+ public static final int SENSOR_REFERENCE_ILLUMINANT_ISO_STUDIO_TUNGSTEN = 24;
+
+ //
// Enumeration values for CaptureResult#STATISTICS_SCENE_FLICKER
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 408e532..c8668f5 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -390,7 +390,7 @@
/**
* <p>Gains applying to Bayer raw color channels for
- * white-balance</p>
+ * white-balance.</p>
* <p>The 4-channel white-balance gains are defined in
* the order of <code>[R G_even G_odd B]</code>, where <code>G_even</code> is the gain
* for green pixels on even rows of the output, and <code>G_odd</code>
@@ -398,11 +398,11 @@
* does not support a separate gain for even/odd green channels,
* it should use the <code>G_even</code> value, and write <code>G_odd</code> equal to
* <code>G_even</code> in the output result metadata.</p>
- * <p>This array is either set by HAL when the request
+ * <p>This array is either set by the camera device when the request
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
- * <p>The output should be the gains actually applied by the HAL to
+ * <p>The output should be the gains actually applied by the camera device to
* the current frame.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -536,9 +536,9 @@
* bottom-right pixel in the active pixel array. The weight
* should be nonnegative.</p>
* <p>If all regions have 0 weight, then no specific metering area
- * needs to be used by the HAL. If the metering region is
- * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
- * should ignore the sections outside the region and output the
+ * 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>
*
* @see CaptureRequest#SCALER_CROP_REGION
@@ -579,13 +579,15 @@
/**
* <p>Whether AF is currently enabled, and what
* mode it is set to</p>
- * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO.</p>
+ * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
+ * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} > 0</code>).</p>
* <p>If the lens is controlled by the camera device auto-focus algorithm,
* the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
* in result metadata.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see CaptureRequest#CONTROL_MODE
+ * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
* @see #CONTROL_AF_MODE_OFF
* @see #CONTROL_AF_MODE_AUTO
* @see #CONTROL_AF_MODE_MACRO
@@ -609,9 +611,9 @@
* bottom-right pixel in the active pixel array. The weight
* should be nonnegative.</p>
* <p>If all regions have 0 weight, then no specific focus area
- * needs to be used by the HAL. If the focusing region is
- * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
- * should ignore the sections outside the region and output the
+ * 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>
*
* @see CaptureRequest#SCALER_CROP_REGION
@@ -651,14 +653,14 @@
/**
* <p>Whether AWB is currently setting the color
* transform fields, and what its illumination target
- * is</p>
+ * is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
* <p>When set to the ON mode, the camera device's auto white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
* <p>When set to the OFF mode, the camera device's auto white balance
- * routine is disabled. The applicantion manually controls the white
+ * routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
* <p>When set to any other modes, the camera device's auto white balance
@@ -695,10 +697,10 @@
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
* should be nonnegative.</p>
- * <p>If all regions have 0 weight, then no specific metering area
- * needs to be used by the HAL. If the metering region is
- * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
- * should ignore the sections outside the region and output the
+ * <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>
*
* @see CaptureRequest#SCALER_CROP_REGION
@@ -753,7 +755,7 @@
/**
* <p>Overall mode of 3A control
- * routines</p>
+ * routines.</p>
* <p>High-level 3A control. When set to OFF, all 3A control
* by the camera device is disabled. The application must set the fields for
* capture parameters itself.</p>
@@ -830,9 +832,9 @@
/**
* <p>Operation mode for edge
- * enhancement</p>
+ * enhancement.</p>
* <p>Edge/sharpness/detail enhancement. OFF means no
- * enhancement will be applied by the HAL.</p>
+ * enhancement will be applied by the camera device.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined enhancement
* will be applied. HIGH_QUALITY mode indicates that the
* camera device will use the highest-quality enhancement algorithms,
@@ -1044,7 +1046,7 @@
* <p>Mode of operation for the noise reduction
* algorithm</p>
* <p>Noise filtering control. OFF means no noise reduction
- * will be applied by the HAL.</p>
+ * will be applied by the camera device.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
@@ -1285,8 +1287,8 @@
new Key<Integer>("android.statistics.faceDetectMode", int.class);
/**
- * <p>Whether the HAL needs to output the lens
- * shading map in output result metadata</p>
+ * <p>Whether the camera device will output the lens
+ * shading map in output result metadata.</p>
* <p>When set to ON,
* {@link CaptureResult#STATISTICS_LENS_SHADING_MAP android.statistics.lensShadingMap} must be provided in
* the output result metadata.</p>
@@ -1329,7 +1331,7 @@
* <p>Each channel's curve is defined by an array of control points:</p>
* <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} =
* [ P0in, P0out, P1in, P1out, P2in, P2out, P3in, P3out, ..., PNin, PNout ]
- * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
+ * 2 <= N <= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
* <p>These are sorted in order of increasing <code>Pin</code>; it is always
* guaranteed that input values 0.0 and 1.0 are included in the list to
* define a complete mapping. For input values between control points,
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 345b52c..0749edd 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -143,7 +143,7 @@
/**
* <p>Gains applying to Bayer raw color channels for
- * white-balance</p>
+ * white-balance.</p>
* <p>The 4-channel white-balance gains are defined in
* the order of <code>[R G_even G_odd B]</code>, where <code>G_even</code> is the gain
* for green pixels on even rows of the output, and <code>G_odd</code>
@@ -151,11 +151,11 @@
* does not support a separate gain for even/odd green channels,
* it should use the <code>G_even</code> value, and write <code>G_odd</code> equal to
* <code>G_even</code> in the output result metadata.</p>
- * <p>This array is either set by HAL when the request
+ * <p>This array is either set by the camera device when the request
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is not TRANSFORM_MATRIX, or
* directly by the application in the request when the
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} is TRANSFORM_MATRIX.</p>
- * <p>The output should be the gains actually applied by the HAL to
+ * <p>The output should be the gains actually applied by the camera device to
* the current frame.</p>
*
* @see CaptureRequest#COLOR_CORRECTION_MODE
@@ -225,9 +225,9 @@
* bottom-right pixel in the active pixel array. The weight
* should be nonnegative.</p>
* <p>If all regions have 0 weight, then no specific metering area
- * needs to be used by the HAL. If the metering region is
- * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
- * should ignore the sections outside the region and output the
+ * 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>
*
* @see CaptureRequest#SCALER_CROP_REGION
@@ -370,6 +370,54 @@
* </tr>
* </tbody>
* </table>
+ * <p>For the above table, the camera device may skip reporting any state changes that happen
+ * without application intervention (i.e. mode switch, trigger, locking). Any state that
+ * can be skipped in that manner is called a transient state.</p>
+ * <p>For example, for above AE modes (AE_MODE_ON_*), in addition to the state transitions
+ * listed in above table, it is also legal for the camera device to skip one or more
+ * transient states between two results. See below table for examples:</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">State</th>
+ * <th align="center">Transition Cause</th>
+ * <th align="center">New State</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">INACTIVE</td>
+ * <td align="center">Camera device finished AE scan</td>
+ * <td align="center">CONVERGED</td>
+ * <td align="center">Values are already good, transient states are skipped by camera device.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">Any state</td>
+ * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
+ * <td align="center">FLASH_REQUIRED</td>
+ * <td align="center">Converged but too dark w/o flash after a precapture sequence, transient states are skipped by camera device.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">Any state</td>
+ * <td align="center">{@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is START, sequence done</td>
+ * <td align="center">CONVERGED</td>
+ * <td align="center">Converged after a precapture sequence, transient states are skipped by camera device.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">CONVERGED</td>
+ * <td align="center">Camera device finished AE scan</td>
+ * <td align="center">FLASH_REQUIRED</td>
+ * <td align="center">Converged but too dark w/o flash after a new scan, transient states are skipped by camera device.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">FLASH_REQUIRED</td>
+ * <td align="center">Camera device finished AE scan</td>
+ * <td align="center">CONVERGED</td>
+ * <td align="center">Converged after a new scan, transient states are skipped by camera device.</td>
+ * </tr>
+ * </tbody>
+ * </table>
*
* @see CaptureRequest#CONTROL_AE_LOCK
* @see CaptureRequest#CONTROL_AE_MODE
@@ -389,13 +437,15 @@
/**
* <p>Whether AF is currently enabled, and what
* mode it is set to</p>
- * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO.</p>
+ * <p>Only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} = AUTO and the lens is not fixed focus
+ * (i.e. <code>{@link CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE android.lens.info.minimumFocusDistance} > 0</code>).</p>
* <p>If the lens is controlled by the camera device auto-focus algorithm,
* the camera device will report the current AF status in {@link CaptureResult#CONTROL_AF_STATE android.control.afState}
* in result metadata.</p>
*
* @see CaptureResult#CONTROL_AF_STATE
* @see CaptureRequest#CONTROL_MODE
+ * @see CameraCharacteristics#LENS_INFO_MINIMUM_FOCUS_DISTANCE
* @see #CONTROL_AF_MODE_OFF
* @see #CONTROL_AF_MODE_AUTO
* @see #CONTROL_AF_MODE_MACRO
@@ -419,9 +469,9 @@
* bottom-right pixel in the active pixel array. The weight
* should be nonnegative.</p>
* <p>If all regions have 0 weight, then no specific focus area
- * needs to be used by the HAL. If the focusing region is
- * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
- * should ignore the sections outside the region and output the
+ * 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>
*
* @see CaptureRequest#SCALER_CROP_REGION
@@ -431,7 +481,7 @@
new Key<int[]>("android.control.afRegions", int[].class);
/**
- * <p>Current state of AF algorithm</p>
+ * <p>Current state of AF algorithm.</p>
* <p>Switching between or enabling AF modes ({@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}) always
* resets the AF state to INACTIVE. Similarly, switching between {@link CaptureRequest#CONTROL_MODE android.control.mode},
* or {@link CaptureRequest#CONTROL_SCENE_MODE android.control.sceneMode} if <code>{@link CaptureRequest#CONTROL_MODE android.control.mode} == USE_SCENE_MODE</code> resets all
@@ -529,6 +579,48 @@
* </tr>
* </tbody>
* </table>
+ * <p>For the above table, the camera device may skip reporting any state changes that happen
+ * without application intervention (i.e. mode switch, trigger, locking). Any state that
+ * can be skipped in that manner is called a transient state.</p>
+ * <p>For example, for these AF modes (AF_MODE_AUTO and AF_MODE_MACRO), in addition to the
+ * state transitions listed in above table, it is also legal for the camera device to skip
+ * one or more transient states between two results. See below table for examples:</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">State</th>
+ * <th align="center">Transition Cause</th>
+ * <th align="center">New State</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">INACTIVE</td>
+ * <td align="center">AF_TRIGGER</td>
+ * <td align="center">FOCUSED_LOCKED</td>
+ * <td align="center">Focus is already good or good after a scan, lens is now locked.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">INACTIVE</td>
+ * <td align="center">AF_TRIGGER</td>
+ * <td align="center">NOT_FOCUSED_LOCKED</td>
+ * <td align="center">Focus failed after a scan, lens is now locked.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">FOCUSED_LOCKED</td>
+ * <td align="center">AF_TRIGGER</td>
+ * <td align="center">FOCUSED_LOCKED</td>
+ * <td align="center">Focus is already good or good after a scan, lens is now locked.</td>
+ * </tr>
+ * <tr>
+ * <td align="center">NOT_FOCUSED_LOCKED</td>
+ * <td align="center">AF_TRIGGER</td>
+ * <td align="center">FOCUSED_LOCKED</td>
+ * <td align="center">Focus is good after a scan, lens is not locked.</td>
+ * </tr>
+ * </tbody>
+ * </table>
* <p>When {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode} is AF_MODE_CONTINUOUS_VIDEO:</p>
* <table>
* <thead>
@@ -735,6 +827,41 @@
* </tr>
* </tbody>
* </table>
+ * <p>When switch between AF_MODE_CONTINUOUS_* (CAF modes) and AF_MODE_AUTO/AF_MODE_MACRO
+ * (AUTO modes), the initial INACTIVE or PASSIVE_SCAN states may be skipped by the
+ * camera device. When a trigger is included in a mode switch request, the trigger
+ * will be evaluated in the context of the new mode in the request.
+ * See below table for examples:</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">State</th>
+ * <th align="center">Transition Cause</th>
+ * <th align="center">New State</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">any state</td>
+ * <td align="center">CAF-->AUTO mode switch</td>
+ * <td align="center">INACTIVE</td>
+ * <td align="center">Mode switch without trigger, initial state must be INACTIVE</td>
+ * </tr>
+ * <tr>
+ * <td align="center">any state</td>
+ * <td align="center">CAF-->AUTO mode switch with AF_TRIGGER</td>
+ * <td align="center">trigger-reachable states from INACTIVE</td>
+ * <td align="center">Mode switch with trigger, INACTIVE is skipped</td>
+ * </tr>
+ * <tr>
+ * <td align="center">any state</td>
+ * <td align="center">AUTO-->CAF mode switch</td>
+ * <td align="center">passively reachable states from INACTIVE</td>
+ * <td align="center">Mode switch without trigger, passive transient state is skipped</td>
+ * </tr>
+ * </tbody>
+ * </table>
*
* @see CaptureRequest#CONTROL_AF_MODE
* @see CaptureRequest#CONTROL_MODE
@@ -764,14 +891,14 @@
/**
* <p>Whether AWB is currently setting the color
* transform fields, and what its illumination target
- * is</p>
+ * is.</p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_MODE android.control.mode} is AUTO.</p>
* <p>When set to the ON mode, the camera device's auto white balance
* routine is enabled, overriding the application's selected
* {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains} and
* {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
* <p>When set to the OFF mode, the camera device's auto white balance
- * routine is disabled. The applicantion manually controls the white
+ * routine is disabled. The application manually controls the white
* balance by {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform}, {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}
* and {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode}.</p>
* <p>When set to any other modes, the camera device's auto white balance
@@ -808,10 +935,10 @@
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.height - 1) being the
* bottom-right pixel in the active pixel array. The weight
* should be nonnegative.</p>
- * <p>If all regions have 0 weight, then no specific metering area
- * needs to be used by the HAL. If the metering region is
- * outside the current {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion}, the HAL
- * should ignore the sections outside the region and output the
+ * <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>
*
* @see CaptureRequest#SCALER_CROP_REGION
@@ -905,11 +1032,35 @@
* <td align="center">SEARCHING</td>
* <td align="center">Values not good after unlock</td>
* </tr>
+ * </tbody>
+ * </table>
+ * <p>For the above table, the camera device may skip reporting any state changes that happen
+ * without application intervention (i.e. mode switch, trigger, locking). Any state that
+ * can be skipped in that manner is called a transient state.</p>
+ * <p>For example, for this AWB mode (AWB_MODE_AUTO), in addition to the state transitions
+ * listed in above table, it is also legal for the camera device to skip one or more
+ * transient states between two results. See below table for examples:</p>
+ * <table>
+ * <thead>
+ * <tr>
+ * <th align="center">State</th>
+ * <th align="center">Transition Cause</th>
+ * <th align="center">New State</th>
+ * <th align="center">Notes</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td align="center">INACTIVE</td>
+ * <td align="center">Camera device finished AWB scan</td>
+ * <td align="center">CONVERGED</td>
+ * <td align="center">Values are already good, transient states are skipped by camera device.</td>
+ * </tr>
* <tr>
* <td align="center">LOCKED</td>
* <td align="center">{@link CaptureRequest#CONTROL_AWB_LOCK android.control.awbLock} is OFF</td>
* <td align="center">CONVERGED</td>
- * <td align="center">Values good after unlock</td>
+ * <td align="center">Values good after unlock, transient states are skipped by camera device.</td>
* </tr>
* </tbody>
* </table>
@@ -928,7 +1079,7 @@
/**
* <p>Overall mode of 3A control
- * routines</p>
+ * routines.</p>
* <p>High-level 3A control. When set to OFF, all 3A control
* by the camera device is disabled. The application must set the fields for
* capture parameters itself.</p>
@@ -956,9 +1107,9 @@
/**
* <p>Operation mode for edge
- * enhancement</p>
+ * enhancement.</p>
* <p>Edge/sharpness/detail enhancement. OFF means no
- * enhancement will be applied by the HAL.</p>
+ * enhancement will be applied by the camera device.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined enhancement
* will be applied. HIGH_QUALITY mode indicates that the
* camera device will use the highest-quality enhancement algorithms,
@@ -1236,7 +1387,7 @@
* <p>Mode of operation for the noise reduction
* algorithm</p>
* <p>Noise filtering control. OFF means no noise reduction
- * will be applied by the HAL.</p>
+ * will be applied by the camera device.</p>
* <p>FAST/HIGH_QUALITY both mean camera device determined noise filtering
* will be applied. HIGH_QUALITY mode indicates that the camera device
* will use the highest-quality noise filtering algorithms,
@@ -1262,7 +1413,7 @@
* before the FINAL buffer for frame 4. PARTIAL buffers may be returned
* in any order relative to other frames, but all PARTIAL buffers for a given
* capture must arrive before the FINAL buffer for that capture. This entry may
- * only be used by the HAL if quirks.usePartialResult is set to 1.</p>
+ * only be used by the camera device if quirks.usePartialResult is set to 1.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
* @hide
*/
@@ -1459,6 +1610,36 @@
new Key<Float>("android.sensor.temperature", float.class);
/**
+ * <p>A reference illumination source roughly matching the current scene
+ * illumination, which is used to describe the sensor color space
+ * transformations.</p>
+ * <p>The values in this tag correspond to the values defined for the
+ * EXIF LightSource tag. These illuminants are standard light sources
+ * that are often used for calibrating camera devices.</p>
+ * @see #SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_TUNGSTEN
+ * @see #SENSOR_REFERENCE_ILLUMINANT_FLASH
+ * @see #SENSOR_REFERENCE_ILLUMINANT_FINE_WEATHER
+ * @see #SENSOR_REFERENCE_ILLUMINANT_CLOUDY_WEATHER
+ * @see #SENSOR_REFERENCE_ILLUMINANT_SHADE
+ * @see #SENSOR_REFERENCE_ILLUMINANT_DAYLIGHT_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_DAY_WHITE_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_COOL_WHITE_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_WHITE_FLUORESCENT
+ * @see #SENSOR_REFERENCE_ILLUMINANT_STANDARD_A
+ * @see #SENSOR_REFERENCE_ILLUMINANT_STANDARD_B
+ * @see #SENSOR_REFERENCE_ILLUMINANT_STANDARD_C
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D55
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D65
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D75
+ * @see #SENSOR_REFERENCE_ILLUMINANT_D50
+ * @see #SENSOR_REFERENCE_ILLUMINANT_ISO_STUDIO_TUNGSTEN
+ */
+ public static final Key<Integer> SENSOR_REFERENCE_ILLUMINANT =
+ new Key<Integer>("android.sensor.referenceIlluminant", int.class);
+
+ /**
* <p>A per-device calibration transform matrix to be applied after the
* color space transform when rendering the raw image buffer.</p>
* <p>This matrix is expressed as a 3x3 matrix in row-major-order, and
@@ -1536,6 +1717,39 @@
new Key<float[]>("android.sensor.profileToneCurve", float[].class);
/**
+ * <p>The worst-case divergence between Bayer green channels.</p>
+ * <p>This value is an estimate of the worst case split between the
+ * Bayer green channels in the red and blue rows in the sensor color
+ * filter array.</p>
+ * <p>The green split is calculated as follows:</p>
+ * <ol>
+ * <li>A representative 5x5 pixel window W within the active
+ * sensor array is chosen.</li>
+ * <li>The arithmetic mean of the green channels from the red
+ * rows (mean_Gr) within W is computed.</li>
+ * <li>The arithmetic mean of the green channels from the blue
+ * rows (mean_Gb) within W is computed.</li>
+ * <li>The maximum ratio R of the two means is computed as follows:
+ * <code>R = max((mean_Gr + 1)/(mean_Gb + 1), (mean_Gb + 1)/(mean_Gr + 1))</code></li>
+ * </ol>
+ * <p>The ratio R is the green split divergence reported for this property,
+ * which represents how much the green channels differ in the mosaic
+ * pattern. This value is typically used to determine the treatment of
+ * the green mosaic channels when demosaicing.</p>
+ * <p>The green split value can be roughly interpreted as follows:</p>
+ * <ul>
+ * <li>R < 1.03 is a negligible split (<3% divergence).</li>
+ * <li>1.20 <= R >= 1.03 will require some software
+ * correction to avoid demosaic errors (3-20% divergence).</li>
+ * <li>R > 1.20 will require strong software correction to produce
+ * a usuable image (>20% divergence).</li>
+ * </ul>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ */
+ public static final Key<Float> SENSOR_GREEN_SPLIT =
+ new Key<Float>("android.sensor.greenSplit", float.class);
+
+ /**
* <p>When enabled, the sensor sends a test pattern instead of
* doing a real exposure from the camera.</p>
* <p>When a test pattern is enabled, all manual sensor controls specified
@@ -1692,7 +1906,7 @@
/**
* <p>The best-fit color channel gains calculated
- * by the HAL's statistics units for the current output frame</p>
+ * by the camera device's statistics units for the current output frame.</p>
* <p>This may be different than the gains used for this frame,
* since statistics processing on data from a new frame
* typically completes after the transform has already been
@@ -1711,11 +1925,11 @@
/**
* <p>The best-fit color transform matrix estimate
- * calculated by the HAL's statistics units for the current
- * output frame</p>
- * <p>The HAL must provide the estimate from its
+ * calculated by the camera device's statistics units for the current
+ * output frame.</p>
+ * <p>The camera device will provide the estimate from its
* statistics unit on the white balance transforms to use
- * for the next frame. These are the values the HAL believes
+ * for the next frame. These are the values the camera device believes
* are the best fit for the current output frame. This may
* be different than the transform used for this frame, since
* statistics processing on data from a new frame typically
@@ -1788,7 +2002,7 @@
* <p>Each channel's curve is defined by an array of control points:</p>
* <pre><code>{@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed} =
* [ P0in, P0out, P1in, P1out, P2in, P2out, P3in, P3out, ..., PNin, PNout ]
- * 2 &lt;= N &lt;= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
+ * 2 <= N <= {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS android.tonemap.maxCurvePoints}</code></pre>
* <p>These are sorted in order of increasing <code>Pin</code>; it is always
* guaranteed that input values 0.0 and 1.0 are included in the list to
* define a complete mapping. For input values between control points,
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3a35cb9..e6b9d4c 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -400,6 +400,8 @@
private final IConnectivityManager mService;
+ private final String mPackageName;
+
/**
* Tests if a given integer represents a valid network type.
* @param networkType the type to be tested
@@ -811,7 +813,7 @@
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
byte[] address = hostAddress.getAddress();
try {
- return mService.requestRouteToHostAddress(networkType, address);
+ return mService.requestRouteToHostAddress(networkType, address, mPackageName);
} catch (RemoteException e) {
return false;
}
@@ -907,8 +909,9 @@
/**
* {@hide}
*/
- public ConnectivityManager(IConnectivityManager service) {
+ public ConnectivityManager(IConnectivityManager service, String packageName) {
mService = checkNotNull(service, "missing IConnectivityManager");
+ mPackageName = checkNotNull(packageName, "missing package name");
}
/** {@hide} */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b3217eb..381a817 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -71,9 +71,9 @@
int stopUsingNetworkFeature(int networkType, in String feature);
- boolean requestRouteToHost(int networkType, int hostAddress);
+ boolean requestRouteToHost(int networkType, int hostAddress, String packageName);
- boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
+ boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName);
boolean getMobileDataEnabled();
void setMobileDataEnabled(boolean enabled);
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index a7aae2a..25514f4 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -44,6 +44,8 @@
public static final String IFACE_ALL = null;
/** {@link #uid} value when UID details unavailable. */
public static final int UID_ALL = -1;
+ /** {@link #tag} value matching any tag. */
+ public static final int TAG_ALL = -1;
/** {@link #set} value when all sets combined. */
public static final int SET_ALL = -1;
/** {@link #set} value where background data is accounted. */
@@ -59,8 +61,9 @@
* {@link SystemClock#elapsedRealtime()} timestamp when this data was
* generated.
*/
- private final long elapsedRealtime;
+ private long elapsedRealtime;
private int size;
+ private int capacity;
private String[] iface;
private int[] uid;
private int[] set;
@@ -152,20 +155,27 @@
public NetworkStats(long elapsedRealtime, int initialSize) {
this.elapsedRealtime = elapsedRealtime;
this.size = 0;
- this.iface = new String[initialSize];
- this.uid = new int[initialSize];
- this.set = new int[initialSize];
- this.tag = new int[initialSize];
- this.rxBytes = new long[initialSize];
- this.rxPackets = new long[initialSize];
- this.txBytes = new long[initialSize];
- this.txPackets = new long[initialSize];
- this.operations = new long[initialSize];
+ if (initialSize >= 0) {
+ this.capacity = initialSize;
+ this.iface = new String[initialSize];
+ this.uid = new int[initialSize];
+ this.set = new int[initialSize];
+ this.tag = new int[initialSize];
+ this.rxBytes = new long[initialSize];
+ this.rxPackets = new long[initialSize];
+ this.txBytes = new long[initialSize];
+ this.txPackets = new long[initialSize];
+ this.operations = new long[initialSize];
+ } else {
+ // Special case for use by NetworkStatsFactory to start out *really* empty.
+ this.capacity = 0;
+ }
}
public NetworkStats(Parcel parcel) {
elapsedRealtime = parcel.readLong();
size = parcel.readInt();
+ capacity = parcel.readInt();
iface = parcel.createStringArray();
uid = parcel.createIntArray();
set = parcel.createIntArray();
@@ -181,6 +191,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(elapsedRealtime);
dest.writeInt(size);
+ dest.writeInt(capacity);
dest.writeStringArray(iface);
dest.writeIntArray(uid);
dest.writeIntArray(set);
@@ -222,8 +233,8 @@
* object can be recycled across multiple calls.
*/
public NetworkStats addValues(Entry entry) {
- if (size >= this.iface.length) {
- final int newLength = Math.max(iface.length, 10) * 3 / 2;
+ if (size >= capacity) {
+ final int newLength = Math.max(size, 10) * 3 / 2;
iface = Arrays.copyOf(iface, newLength);
uid = Arrays.copyOf(uid, newLength);
set = Arrays.copyOf(set, newLength);
@@ -233,6 +244,7 @@
txBytes = Arrays.copyOf(txBytes, newLength);
txPackets = Arrays.copyOf(txPackets, newLength);
operations = Arrays.copyOf(operations, newLength);
+ capacity = newLength;
}
iface[size] = entry.iface;
@@ -270,6 +282,10 @@
return elapsedRealtime;
}
+ public void setElapsedRealtime(long time) {
+ elapsedRealtime = time;
+ }
+
/**
* Return age of this {@link NetworkStats} object with respect to
* {@link SystemClock#elapsedRealtime()}.
@@ -284,7 +300,7 @@
@VisibleForTesting
public int internalSize() {
- return iface.length;
+ return capacity;
}
@Deprecated
@@ -507,8 +523,25 @@
* If counters have rolled backwards, they are clamped to {@code 0} and
* reported to the given {@link NonMonotonicObserver}.
*/
- public static <C> NetworkStats subtract(
- NetworkStats left, NetworkStats right, NonMonotonicObserver<C> observer, C cookie) {
+ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
+ NonMonotonicObserver<C> observer, C cookie) {
+ return subtract(left, right, observer, cookie, null);
+ }
+
+ /**
+ * Subtract the two given {@link NetworkStats} objects, returning the delta
+ * between two snapshots in time. Assumes that statistics rows collect over
+ * time, and that none of them have disappeared.
+ * <p>
+ * If counters have rolled backwards, they are clamped to {@code 0} and
+ * reported to the given {@link NonMonotonicObserver}.
+ * <p>
+ * If <var>recycle</var> is supplied, this NetworkStats object will be
+ * reused (and returned) as the result if it is large enough to contain
+ * the data.
+ */
+ public static <C> NetworkStats subtract(NetworkStats left, NetworkStats right,
+ NonMonotonicObserver<C> observer, C cookie, NetworkStats recycle) {
long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime;
if (deltaRealtime < 0) {
if (observer != null) {
@@ -519,7 +552,14 @@
// result will have our rows, and elapsed time between snapshots
final Entry entry = new Entry();
- final NetworkStats result = new NetworkStats(deltaRealtime, left.size);
+ final NetworkStats result;
+ if (recycle != null && recycle.capacity >= left.size) {
+ result = recycle;
+ result.size = 0;
+ result.elapsedRealtime = deltaRealtime;
+ } else {
+ result = new NetworkStats(deltaRealtime, left.size);
+ }
for (int i = 0; i < left.size; i++) {
entry.iface = left.iface[i];
entry.uid = left.uid[i];
diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java
index a7d287b..461e8b8 100644
--- a/core/java/android/net/ProxyDataTracker.java
+++ b/core/java/android/net/ProxyDataTracker.java
@@ -16,13 +16,24 @@
package android.net;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
+import android.os.Messenger;
+import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -31,27 +42,70 @@
* {@hide}
*/
public class ProxyDataTracker extends BaseNetworkStateTracker {
- private static final String NETWORK_TYPE = "PROXY";
private static final String TAG = "ProxyDataTracker";
+ private static final String NETWORK_TYPE = "PROXY";
// TODO: investigate how to get these DNS addresses from the system.
private static final String DNS1 = "8.8.8.8";
private static final String DNS2 = "8.8.4.4";
private static final String REASON_ENABLED = "enabled";
+ private static final String REASON_DISABLED = "disabled";
+ private static final String REASON_PROXY_DOWN = "proxy_down";
+ private static final int MSG_TEAR_DOWN_REQUEST = 1;
+ private static final int MSG_SETUP_REQUEST = 2;
+
+ private static final String PERMISSION_PROXY_STATUS_SENDER =
+ "android.permission.ACCESS_NETWORK_CONDITIONS";
+ private static final String ACTION_PROXY_STATUS_CHANGE =
+ "com.android.net.PROXY_STATUS_CHANGE";
+ private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available";
+ private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder";
+ private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE =
+ "reply_to_messenger_binder_bundle";
+
+ private Handler mTarget;
+ private Messenger mProxyStatusService;
+ private AtomicBoolean mReconnectRequested = new AtomicBoolean(false);
+ private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false);
private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0);
- private final AtomicInteger mReconnectGeneration = new AtomicInteger(0);
+
+ private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) {
+ mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false));
+ if (mIsProxyAvailable.get()) {
+ Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE);
+ if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) {
+ Log.e(TAG, "no messenger binder in the intent to send future requests");
+ mIsProxyAvailable.set(false);
+ return;
+ }
+ mProxyStatusService =
+ new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER));
+ // If there is a pending reconnect request, do it now.
+ if (mReconnectRequested.get()) {
+ reconnect();
+ }
+ } else {
+ setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
+ REASON_PROXY_DOWN, null);
+ }
+ } else {
+ Log.d(TAG, "Unrecognized broadcast intent");
+ }
+ }
+ };
/**
* Create a new ProxyDataTracker
*/
public ProxyDataTracker() {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, "");
- // TODO: update available state according to proxy state.
- mNetworkInfo.setIsAvailable(true);
mLinkProperties = new LinkProperties();
mLinkCapabilities = new LinkCapabilities();
-
+ mNetworkInfo.setIsAvailable(true);
try {
mLinkProperties.addDns(InetAddress.getByName(DNS1));
mLinkProperties.addDns(InetAddress.getByName(DNS2));
@@ -64,11 +118,31 @@
throw new CloneNotSupportedException();
}
+ @Override
+ public void startMonitoring(Context context, Handler target) {
+ mContext = context;
+ mTarget = target;
+ mContext.registerReceiver(mProxyStatusServiceListener,
+ new IntentFilter(ACTION_PROXY_STATUS_CHANGE),
+ PERMISSION_PROXY_STATUS_SENDER,
+ null);
+ }
+
/**
* Disable connectivity to the network.
*/
public boolean teardown() {
- // TODO: tell relevant service to tear down proxy.
+ setTeardownRequested(true);
+ mReconnectRequested.set(false);
+ try {
+ if (mIsProxyAvailable.get() && mProxyStatusService != null) {
+ mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST));
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to connect to proxy status service", e);
+ return false;
+ }
+ setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null);
return true;
}
@@ -76,16 +150,24 @@
* Re-enable proxy data connectivity after a {@link #teardown()}.
*/
public boolean reconnect() {
- if (!isAvailable()) {
- Log.w(TAG, "Reconnect requested even though network is disabled. Bailing.");
+ mReconnectRequested.set(true);
+ setTeardownRequested(false);
+ if (!mIsProxyAvailable.get()) {
+ Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing.");
return false;
}
- setTeardownRequested(false);
- mReconnectGeneration.incrementAndGet();
- // TODO: tell relevant service to setup proxy. Set state to connected only if setup
- // succeeds.
- setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null);
+ setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null);
+ try {
+ mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to connect to proxy status service", e);
+ setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null);
+ return false;
+ }
+ // We'll assume proxy is set up successfully. If not, a status change broadcast will be
+ // received afterwards to indicate any failure.
+ setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null);
return true;
}
@@ -116,7 +198,7 @@
private void setDetailedState(NetworkInfo.DetailedState state, String reason,
String extraInfo) {
mNetworkInfo.setDetailedState(state, reason, extraInfo);
- Message msg = getTargetHandler().obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
+ Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 345ff82..dfba208 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -171,6 +171,10 @@
private static final String SIGNAL_STRENGTH_COUNT_DATA = "sgc";
private static final String DATA_CONNECTION_TIME_DATA = "dct";
private static final String DATA_CONNECTION_COUNT_DATA = "dcc";
+ private static final String WIFI_STATE_TIME_DATA = "wst";
+ private static final String WIFI_STATE_COUNT_DATA = "wsc";
+ private static final String BLUETOOTH_STATE_TIME_DATA = "bst";
+ private static final String BLUETOOTH_STATE_COUNT_DATA = "bsc";
private static final String POWER_USE_SUMMARY_DATA = "pws";
private static final String POWER_USE_ITEM_DATA = "pwi";
@@ -275,22 +279,22 @@
*/
public abstract int getUid();
- public abstract void noteWifiRunningLocked();
- public abstract void noteWifiStoppedLocked();
- public abstract void noteFullWifiLockAcquiredLocked();
- public abstract void noteFullWifiLockReleasedLocked();
- public abstract void noteWifiScanStartedLocked();
- public abstract void noteWifiScanStoppedLocked();
- public abstract void noteWifiBatchedScanStartedLocked(int csph);
- public abstract void noteWifiBatchedScanStoppedLocked();
- public abstract void noteWifiMulticastEnabledLocked();
- public abstract void noteWifiMulticastDisabledLocked();
- public abstract void noteAudioTurnedOnLocked();
- public abstract void noteAudioTurnedOffLocked();
- public abstract void noteVideoTurnedOnLocked();
- public abstract void noteVideoTurnedOffLocked();
- public abstract void noteActivityResumedLocked();
- public abstract void noteActivityPausedLocked();
+ public abstract void noteWifiRunningLocked(long elapsedRealtime);
+ public abstract void noteWifiStoppedLocked(long elapsedRealtime);
+ public abstract void noteFullWifiLockAcquiredLocked(long elapsedRealtime);
+ public abstract void noteFullWifiLockReleasedLocked(long elapsedRealtime);
+ public abstract void noteWifiScanStartedLocked(long elapsedRealtime);
+ public abstract void noteWifiScanStoppedLocked(long elapsedRealtime);
+ public abstract void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtime);
+ public abstract void noteWifiBatchedScanStoppedLocked(long elapsedRealtime);
+ public abstract void noteWifiMulticastEnabledLocked(long elapsedRealtime);
+ public abstract void noteWifiMulticastDisabledLocked(long elapsedRealtime);
+ public abstract void noteAudioTurnedOnLocked(long elapsedRealtime);
+ public abstract void noteAudioTurnedOffLocked(long elapsedRealtime);
+ public abstract void noteVideoTurnedOnLocked(long elapsedRealtime);
+ public abstract void noteVideoTurnedOffLocked(long elapsedRealtime);
+ public abstract void noteActivityResumedLocked(long elapsedRealtime);
+ public abstract void noteActivityPausedLocked(long elapsedRealtime);
public abstract long getWifiRunningTime(long batteryRealtime, int which);
public abstract long getFullWifiLockTime(long batteryRealtime, int which);
public abstract long getWifiScanTime(long batteryRealtime, int which);
@@ -549,8 +553,9 @@
public static final int STATE_SENSOR_ON_FLAG = 1<<30;
public static final int STATE_GPS_ON_FLAG = 1<<29;
public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
- public static final int STATE_WIFI_SCAN_FLAG = 1<<29;
+ public static final int STATE_WIFI_SCAN_FLAG = 1<<27;
public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
+ public static final int STATE_MOBILE_RADIO_ACTIVE_FLAG = 1<<25;
public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
// These are on the lower bits used for the command; if they change
// we need to write another int of data.
@@ -882,6 +887,15 @@
*/
public abstract int getPhoneSignalStrengthCount(int strengthBin, int which);
+ /**
+ * Returns the time in microseconds that the mobile network has been active
+ * (in a high power state).
+ *
+ * {@hide}
+ */
+ public abstract long getMobileRadioActiveTime(long batteryRealtime, int which);
+
+
public static final int DATA_CONNECTION_NONE = 0;
public static final int DATA_CONNECTION_GPRS = 1;
public static final int DATA_CONNECTION_EDGE = 2;
@@ -933,6 +947,7 @@
new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"),
new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
+ new BitDescription(HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG, "mobile_radio", "Pr"),
new BitDescription(HistoryItem.STATE_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
@@ -983,6 +998,37 @@
*/
public abstract long getGlobalWifiRunningTime(long batteryRealtime, int which);
+ public static final int WIFI_STATE_OFF = 0;
+ public static final int WIFI_STATE_OFF_SCANNING = 1;
+ public static final int WIFI_STATE_ON_NO_NETWORKS = 2;
+ public static final int WIFI_STATE_ON_DISCONNECTED = 3;
+ public static final int WIFI_STATE_ON_CONNECTED_STA = 4;
+ public static final int WIFI_STATE_ON_CONNECTED_P2P = 5;
+ public static final int WIFI_STATE_ON_CONNECTED_STA_P2P = 6;
+ public static final int WIFI_STATE_SOFT_AP = 7;
+
+ static final String[] WIFI_STATE_NAMES = {
+ "off", "scanning", "no_net", "disconn",
+ "sta", "p2p", "sta_p2p", "soft_ap"
+ };
+
+ public static final int NUM_WIFI_STATES = WIFI_STATE_SOFT_AP+1;
+
+ /**
+ * Returns the time in microseconds that WiFi has been running in the given state.
+ *
+ * {@hide}
+ */
+ public abstract long getWifiStateTime(int wifiState,
+ long batteryRealtime, int which);
+
+ /**
+ * Returns the number of times that WiFi has entered the given state.
+ *
+ * {@hide}
+ */
+ public abstract int getWifiStateCount(int wifiState, int which);
+
/**
* Returns the time in microseconds that bluetooth has been on while the device was
* running on battery.
@@ -993,6 +1039,33 @@
public abstract int getBluetoothPingCount();
+ public static final int BLUETOOTH_STATE_INACTIVE = 0;
+ public static final int BLUETOOTH_STATE_LOW = 1;
+ public static final int BLUETOOTH_STATE_MEDIUM = 2;
+ public static final int BLUETOOTH_STATE_HIGH = 3;
+
+ static final String[] BLUETOOTH_STATE_NAMES = {
+ "inactive", "low", "med", "high"
+ };
+
+ public static final int NUM_BLUETOOTH_STATES = BLUETOOTH_STATE_HIGH +1;
+
+ /**
+ * Returns the time in microseconds that Bluetooth has been running in the
+ * given active state.
+ *
+ * {@hide}
+ */
+ public abstract long getBluetoothStateTime(int bluetoothState,
+ long batteryRealtime, int which);
+
+ /**
+ * Returns the number of times that Bluetooth has entered the given active state.
+ *
+ * {@hide}
+ */
+ public abstract int getBluetoothStateCount(int bluetoothState, int which);
+
public static final int NETWORK_MOBILE_RX_DATA = 0;
public static final int NETWORK_MOBILE_TX_DATA = 1;
public static final int NETWORK_WIFI_RX_DATA = 2;
@@ -1026,19 +1099,6 @@
public abstract long getBatteryUptime(long curTime);
/**
- * @deprecated use getRadioDataUptime
- */
- public long getRadioDataUptimeMs() {
- return getRadioDataUptime() / 1000;
- }
-
- /**
- * Returns the time that the radio was on for data transfers.
- * @return the uptime in microseconds while unplugged
- */
- public abstract long getRadioDataUptime();
-
- /**
* Returns the current battery realtime in microseconds.
*
* @param curTime the amount of elapsed realtime in microseconds.
@@ -1374,7 +1434,7 @@
wifiRunningTime / 1000, bluetoothOnTime / 1000,
mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
fullWakeLockTimeTotal, partialWakeLockTimeTotal,
- getInputEventCount(which));
+ getInputEventCount(which), getMobileRadioActiveTime(batteryRealtime, which));
// Dump screen brightness stats
Object[] args = new Object[NUM_SCREEN_BRIGHTNESS_BINS];
@@ -1395,7 +1455,7 @@
args[i] = getPhoneSignalStrengthCount(i, which);
}
dumpLine(pw, 0 /* uid */, category, SIGNAL_STRENGTH_COUNT_DATA, args);
-
+
// Dump network type stats
args = new Object[NUM_DATA_CONNECTION_TYPES];
for (int i=0; i<NUM_DATA_CONNECTION_TYPES; i++) {
@@ -1406,9 +1466,31 @@
args[i] = getPhoneDataConnectionCount(i, which);
}
dumpLine(pw, 0 /* uid */, category, DATA_CONNECTION_COUNT_DATA, args);
-
+
+ // Dump wifi state stats
+ args = new Object[NUM_WIFI_STATES];
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ args[i] = getWifiStateTime(i, batteryRealtime, which) / 1000;
+ }
+ dumpLine(pw, 0 /* uid */, category, WIFI_STATE_TIME_DATA, args);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ args[i] = getWifiStateCount(i, which);
+ }
+ dumpLine(pw, 0 /* uid */, category, WIFI_STATE_COUNT_DATA, args);
+
+ // Dump bluetooth state stats
+ args = new Object[NUM_BLUETOOTH_STATES];
+ for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
+ args[i] = getBluetoothStateTime(i, batteryRealtime, which) / 1000;
+ }
+ dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_TIME_DATA, args);
+ for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
+ args[i] = getBluetoothStateCount(i, which);
+ }
+ dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_COUNT_DATA, args);
+
if (which == STATS_SINCE_UNPLUGGED) {
- dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
+ dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
getDischargeCurrentLevel());
}
@@ -1906,9 +1988,8 @@
sb.setLength(0);
sb.append(prefix);
- sb.append(" Radio data uptime when unplugged: ");
- sb.append(getRadioDataUptime() / 1000);
- sb.append(" ms");
+ sb.append(" Mobile radio active time: ");
+ formatTimeMs(sb, getMobileRadioActiveTime(batteryRealtime, which) / 1000);
pw.println(sb.toString());
sb.setLength(0);
@@ -1917,12 +1998,63 @@
sb.append("("); sb.append(formatRatioLocked(wifiOnTime, whichBatteryRealtime));
sb.append("), Wifi running: "); formatTimeMs(sb, wifiRunningTime / 1000);
sb.append("("); sb.append(formatRatioLocked(wifiRunningTime, whichBatteryRealtime));
- sb.append("), Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
+ sb.append(")");
+ pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Wifi states:");
+ didOne = false;
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ final long time = getWifiStateTime(i, batteryRealtime, which);
+ if (time == 0) {
+ continue;
+ }
+ sb.append("\n ");
+ didOne = true;
+ sb.append(WIFI_STATE_NAMES[i]);
+ sb.append(" ");
+ formatTimeMs(sb, time/1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(time, whichBatteryRealtime));
+ sb.append(") ");
+ sb.append(getPhoneDataConnectionCount(i, which));
+ sb.append("x");
+ }
+ if (!didOne) sb.append(" (no activity)");
+ pw.println(sb.toString());
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
sb.append("("); sb.append(formatRatioLocked(bluetoothOnTime, whichBatteryRealtime));
sb.append(")");
pw.println(sb.toString());
-
- pw.println(" ");
+
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Bluetooth states:");
+ didOne = false;
+ for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
+ final long time = getBluetoothStateTime(i, batteryRealtime, which);
+ if (time == 0) {
+ continue;
+ }
+ sb.append("\n ");
+ didOne = true;
+ sb.append(BLUETOOTH_STATE_NAMES[i]);
+ sb.append(" ");
+ formatTimeMs(sb, time/1000);
+ sb.append("(");
+ sb.append(formatRatioLocked(time, whichBatteryRealtime));
+ sb.append(") ");
+ sb.append(getPhoneDataConnectionCount(i, which));
+ sb.append("x");
+ }
+ if (!didOne) sb.append(" (no activity)");
+ pw.println(sb.toString());
+
+ pw.println();
if (which == STATS_SINCE_UNPLUGGED) {
if (getIsOnBattery()) {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 0deaea6..8e0ff08 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1247,9 +1247,6 @@
} else if (v instanceof Parcelable[]) {
writeInt(VAL_PARCELABLEARRAY);
writeParcelableArray((Parcelable[]) v, 0);
- } else if (v instanceof Object[]) {
- writeInt(VAL_OBJECTARRAY);
- writeArray((Object[]) v);
} else if (v instanceof int[]) {
writeInt(VAL_INTARRAY);
writeIntArray((int[]) v);
@@ -1259,12 +1256,20 @@
} else if (v instanceof Byte) {
writeInt(VAL_BYTE);
writeInt((Byte) v);
- } else if (v instanceof Serializable) {
- // Must be last
- writeInt(VAL_SERIALIZABLE);
- writeSerializable((Serializable) v);
} else {
- throw new RuntimeException("Parcel: unable to marshal value " + v);
+ Class<?> clazz = v.getClass();
+ if (clazz.isArray() && clazz.getComponentType() == Object.class) {
+ // Only pure Object[] are written here, Other arrays of non-primitive types are
+ // handled by serialization as this does not record the component type.
+ writeInt(VAL_OBJECTARRAY);
+ writeArray((Object[]) v);
+ } else if (v instanceof Serializable) {
+ // Must be last
+ writeInt(VAL_SERIALIZABLE);
+ writeSerializable((Serializable) v);
+ } else {
+ throw new RuntimeException("Parcel: unable to marshal value " + v);
+ }
}
}
@@ -1455,10 +1460,11 @@
}
/**
- * Use this function for customized exception handling.
- * customized method call this method for all unknown case
- * @param code exception code
- * @param msg exception message
+ * Throw an exception with the given message. Not intended for use
+ * outside the Parcel class.
+ *
+ * @param code Used to determine which exception class to throw.
+ * @param msg The exception message.
*/
public final void readException(int code, String msg) {
switch (code) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 0439eeb..4d4c337 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -191,6 +191,18 @@
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 0x00000020;
/**
+ * Wake lock level: Put the screen in a low power state and allow the CPU to suspend
+ * if no other wake locks are held.
+ * <p>
+ * This is used by the dream manager to implement doze mode. It currently
+ * has no effect unless the power manager is in the dozing state.
+ * </p>
+ *
+ * {@hide}
+ */
+ public static final int DOZE_WAKE_LOCK = 0x00000040;
+
+ /**
* Mask for the wake lock level component of a combined wake lock level and flags integer.
*
* @hide
@@ -437,6 +449,7 @@
case SCREEN_BRIGHT_WAKE_LOCK:
case FULL_WAKE_LOCK:
case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
+ case DOZE_WAKE_LOCK:
break;
default:
throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 729c64b..672df6d 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -16,6 +16,9 @@
package android.os;
+import android.app.IAlarmManager;
+import android.content.Context;
+import android.util.Slog;
/**
* Core timekeeping facilities.
@@ -89,6 +92,8 @@
* </ul>
*/
public final class SystemClock {
+ private static final String TAG = "SystemClock";
+
/**
* This class is uninstantiable.
*/
@@ -134,7 +139,23 @@
*
* @return if the clock was successfully set to the specified time.
*/
- native public static boolean setCurrentTimeMillis(long millis);
+ public static boolean setCurrentTimeMillis(long millis) {
+ IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
+ IAlarmManager mgr = IAlarmManager.Stub.asInterface(b);
+ if (mgr == null) {
+ return false;
+ }
+
+ try {
+ return mgr.setTime(millis);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to set RTC", e);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Unable to set RTC", e);
+ }
+
+ return false;
+ }
/**
* Returns milliseconds since boot, not counting time spent in deep sleep.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 8f6dda1..1ec5cd5 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -164,11 +164,13 @@
/**
* Returns whether the system supports multiple users.
- * @return true if multiple users can be created, false if it is a single user device.
+ * @return true if multiple users can be created by user, false if it is a single user device.
* @hide
*/
public static boolean supportsMultipleUsers() {
- return getMaxSupportedUsers() > 1;
+ return getMaxSupportedUsers() > 1
+ && SystemProperties.getBoolean("fw.show_multiuserui",
+ Resources.getSystem().getBoolean(R.bool.config_enableMultiUserUI));
}
/**
@@ -601,6 +603,26 @@
}
/**
+ * Returns true if the user switcher should be shown, this will be if there
+ * are multiple users that aren't managed profiles.
+ * @hide
+ * @return true if user switcher should be shown.
+ */
+ public boolean isUserSwitcherEnabled() {
+ List<UserInfo> users = getUsers(true);
+ if (users == null) {
+ return false;
+ }
+ int switchableUserCount = 0;
+ for (UserInfo user : users) {
+ if (user.supportsSwitchTo()) {
+ ++switchableUserCount;
+ }
+ }
+ return switchableUserCount > 1;
+ }
+
+ /**
* Returns a serial number on this device for a given userHandle. User handles can be recycled
* when deleting and creating users, but serial numbers are not reused until the device is wiped.
* @param userHandle
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index 51ba2f6..b97734e 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -642,12 +642,13 @@
return _result;
}
- public int changeEncryptionPassword(String password) throws RemoteException {
+ public int changeEncryptionPassword(int type, String password) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeInt(type);
_data.writeString(password);
mRemote.transact(Stub.TRANSACTION_changeEncryptionPassword, _data, _reply, 0);
_reply.readException();
@@ -677,6 +678,22 @@
return _result;
}
+ public int getPasswordType() throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ mRemote.transact(Stub.TRANSACTION_getPasswordType, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
+
public StorageVolume[] getVolumeList() throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
@@ -829,6 +846,8 @@
static final int TRANSACTION_mkdirs = IBinder.FIRST_CALL_TRANSACTION + 34;
+ static final int TRANSACTION_getPasswordType = IBinder.FIRST_CALL_TRANSACTION + 36;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1130,8 +1149,9 @@
}
case TRANSACTION_changeEncryptionPassword: {
data.enforceInterface(DESCRIPTOR);
+ int type = data.readInt();
String password = data.readString();
- int result = changeEncryptionPassword(password);
+ int result = changeEncryptionPassword(type, password);
reply.writeNoException();
reply.writeInt(result);
return true;
@@ -1181,6 +1201,13 @@
reply.writeInt(result);
return true;
}
+ case TRANSACTION_getPasswordType: {
+ data.enforceInterface(DESCRIPTOR);
+ int result = getPasswordType();
+ reply.writeNoException();
+ reply.writeInt(result);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1375,7 +1402,8 @@
/**
* Changes the encryption password.
*/
- public int changeEncryptionPassword(String password) throws RemoteException;
+ public int changeEncryptionPassword(int type, String password)
+ throws RemoteException;
/**
* Verify the encryption password against the stored volume. This method
@@ -1412,4 +1440,10 @@
* external storage data or OBB directory belonging to calling app.
*/
public int mkdirs(String callingPkg, String path) throws RemoteException;
+
+ /**
+ * Determines the type of the encryption password
+ * @return PasswordType
+ */
+ public int getPasswordType() throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index f5e728d..68b91cb 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -645,4 +645,14 @@
return Settings.Global.getLong(mResolver, Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
DEFAULT_FULL_THRESHOLD_BYTES);
}
+
+ /// Consts to match the password types in cryptfs.h
+ /** @hide */
+ public static final int CRYPT_TYPE_PASSWORD = 0;
+ /** @hide */
+ public static final int CRYPT_TYPE_DEFAULT = 1;
+ /** @hide */
+ public static final int CRYPT_TYPE_PATTERN = 2;
+ /** @hide */
+ public static final int CRYPT_TYPE_PIN = 3;
}
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f69cad0..bd576afb 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -169,6 +169,14 @@
*/
public static final String EXTRA_MEDIA_TITLE = "android.intent.extra.title";
/**
+ * The name of the Intent-extra used to define the genre.
+ */
+ public static final String EXTRA_MEDIA_GENRE = "android.intent.extra.genre";
+ /**
+ * The name of the Intent-extra used to define the radio channel.
+ */
+ public static final String EXTRA_MEDIA_RADIO_CHANNEL = "android.intent.extra.radio_channel";
+ /**
* The name of the Intent-extra used to define the search focus. The search focus
* indicates whether the search should be for things related to the artist, album
* or song that is identified by the other extras.
@@ -1389,6 +1397,11 @@
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/audio";
/**
+ * The MIME type for an audio track.
+ */
+ public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/audio";
+
+ /**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = TITLE_KEY;
@@ -1859,6 +1872,13 @@
*/
public static final String DEFAULT_SORT_ORDER = ALBUM_KEY;
}
+
+ public static final class Radio {
+ /**
+ * The MIME type for entries in this table.
+ */
+ public static final String ENTRY_CONTENT_TYPE = "vnd.android.cursor.item/radio";
+ }
}
public static final class Video {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 9332578..18018e2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3468,12 +3468,12 @@
"lock_screen_owner_info_enabled";
/**
- * This preference enables expanding the notification panel even over a securely
- * locked screen, showing only "public" notifications in this case.
+ * When set by a user, allows notifications to be shown atop a securely locked screen
+ * in their full "private" form (same as when the device is unlocked).
* @hide
*/
- public static final String LOCK_SCREEN_ALLOW_NOTIFICATIONS =
- "lock_screen_allow_notifications";
+ public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS =
+ "lock_screen_allow_private_notifications";
/**
* The Logging ID (a unique 64-bit value) as a hex string.
@@ -5254,6 +5254,12 @@
public static final String SMS_SHORT_CODE_RULE = "sms_short_code_rule";
/**
+ * Used to select TCP's default initial receiver window size in segments - defaults to a build config value
+ * @hide
+ */
+ public static final String TCP_DEFAULT_INIT_RWND = "tcp_default_init_rwnd";
+
+ /**
* Used to disable Tethering on a device - defaults to true
* @hide
*/
@@ -6066,6 +6072,15 @@
*/
public static final String POLICY_CONTROL = "policy_control";
+
+ /**
+ * This preference enables notification display even over a securely
+ * locked screen.
+ * @hide
+ */
+ public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS =
+ "lock_screen_show_notifications";
+
/**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
diff --git a/core/java/android/service/dreams/DozeHardware.java b/core/java/android/service/dreams/DozeHardware.java
new file mode 100644
index 0000000..b5e7f43
--- /dev/null
+++ b/core/java/android/service/dreams/DozeHardware.java
@@ -0,0 +1,77 @@
+/**
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.dreams;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides access to low-level hardware features that a dream may use to provide
+ * a richer user experience while dozing.
+ * <p>
+ * This class contains functions that should be called by the dream to configure
+ * hardware before starting to doze and allowing the application processor to suspend.
+ * For example, the dream may provide the hardware with enough information to render
+ * some content on its own without any further assistance from the application processor.
+ * </p><p>
+ * This object is obtained by calling {@link DreamService#getDozeHardware()}.
+ * </p>
+ *
+ * @hide experimental
+ */
+public final class DozeHardware {
+ private static final String TAG = "DozeHardware";
+
+ public static final String MSG_ENABLE_MCU = "enable_mcu";
+
+ public static final byte[] VALUE_ON = "on".getBytes();
+ public static final byte[] VALUE_OFF = "off".getBytes();
+
+ private final IDozeHardware mHardware;
+
+ DozeHardware(IDozeHardware hardware) {
+ mHardware = hardware;
+ }
+
+ /**
+ * Sets whether to enable the microcontroller.
+ *
+ * @param enable If true, enables the MCU otherwise disables it.
+ */
+ public void setEnableMcu(boolean enable) {
+ sendMessage(MSG_ENABLE_MCU, enable ? VALUE_ON : VALUE_OFF);
+ }
+
+ /**
+ * Sends a message to the doze hardware module.
+ *
+ * @param msg The name of the message to send.
+ * @param arg An optional argument data blob, may be null.
+ * @return A result data blob, may be null.
+ */
+ public byte[] sendMessage(String msg, byte[] arg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("msg must not be null");
+ }
+
+ try {
+ return mHardware.sendMessage(msg, arg);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to send message to doze hardware module.", ex);
+ return null;
+ }
+ }
+}
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
new file mode 100644
index 0000000..9f7ddba
--- /dev/null
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dreams;
+
+/**
+ * Dream manager local system service interface.
+ *
+ * @hide Only for use within the system server.
+ */
+public abstract class DreamManagerInternal {
+ /**
+ * Called by the power manager to start a dream.
+ */
+ public abstract void startDream(boolean doze);
+
+ /**
+ * Called by the power manager to stop a dream.
+ */
+ public abstract void stopDream();
+
+ /**
+ * Called by the power manager to determine whether a dream is running.
+ */
+ public abstract boolean isDreaming();
+}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index f6b6c89..1abb1d7 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -20,12 +20,14 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.AlarmManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.os.Handler;
import android.os.IBinder;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Slog;
import android.view.ActionMode;
@@ -42,6 +44,8 @@
import android.view.accessibility.AccessibilityEvent;
import com.android.internal.policy.PolicyManager;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
/**
* Extend this class to implement a custom dream (available to the user as a "Daydream").
@@ -145,19 +149,26 @@
*/
public static final String DREAM_META_DATA = "android.service.dream";
+ private final IDreamManager mSandman;
private final Handler mHandler = new Handler();
private IBinder mWindowToken;
private Window mWindow;
private WindowManager mWindowManager;
- private IDreamManager mSandman;
private boolean mInteractive = false;
private boolean mLowProfile = true;
private boolean mFullscreen = false;
private boolean mScreenBright = true;
private boolean mFinished;
+ private boolean mCanDoze;
+ private boolean mDozing;
+ private DozeHardware mDozeHardware;
private boolean mDebug = false;
+ public DreamService() {
+ mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
+ }
+
/**
* @hide
*/
@@ -444,9 +455,11 @@
* correct interactions with it (seeing when it is cleared etc).
*/
public void setLowProfile(boolean lowProfile) {
- mLowProfile = lowProfile;
- int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
- applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+ if (mLowProfile != lowProfile) {
+ mLowProfile = lowProfile;
+ int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ applySystemUiVisibilityFlags(mLowProfile ? flag : 0, flag);
+ }
}
/**
@@ -467,9 +480,11 @@
* will be cleared.
*/
public void setFullscreen(boolean fullscreen) {
- mFullscreen = fullscreen;
- int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
- applyWindowFlags(mFullscreen ? flag : 0, flag);
+ if (mFullscreen != fullscreen) {
+ mFullscreen = fullscreen;
+ int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ applyWindowFlags(mFullscreen ? flag : 0, flag);
+ }
}
/**
@@ -487,14 +502,16 @@
* @param screenBright True to keep the screen bright while dreaming.
*/
public void setScreenBright(boolean screenBright) {
- mScreenBright = screenBright;
- int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
- applyWindowFlags(mScreenBright ? flag : 0, flag);
+ if (mScreenBright != screenBright) {
+ mScreenBright = screenBright;
+ int flag = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ applyWindowFlags(mScreenBright ? flag : 0, flag);
+ }
}
/**
- * Returns whether or not this dream keeps the screen bright while dreaming. Defaults to false,
- * allowing the screen to dim if necessary.
+ * Returns whether or not this dream keeps the screen bright while dreaming.
+ * Defaults to false, allowing the screen to dim if necessary.
*
* @see #setScreenBright(boolean)
*/
@@ -503,6 +520,119 @@
}
/**
+ * Returns true if this dream is allowed to doze.
+ * <p>
+ * The value returned by this method is only meaningful when the dream has started.
+ * </p>
+ *
+ * @return True if this dream can doze.
+ * @see #startDozing
+ * @hide experimental
+ */
+ public boolean canDoze() {
+ return mCanDoze;
+ }
+
+ /**
+ * Starts dozing, entering a deep dreamy sleep.
+ * <p>
+ * Dozing enables the system to conserve power while the user is not actively interacting
+ * with the device. While dozing, the display will remain on in a low-power state
+ * and will continue to show its previous contents but the application processor and
+ * other system components will be allowed to suspend when possible.
+ * </p><p>
+ * While the application processor is suspended, the dream may stop executing code
+ * for long periods of time. Prior to being suspended, the dream may schedule periodic
+ * wake-ups to render new content by scheduling an alarm with the {@link AlarmManager}.
+ * The dream may also keep the CPU awake by acquiring a
+ * {@link android.os.PowerManager#PARTIAL_WAKE_LOCK partial wake lock} when necessary.
+ * Note that since the purpose of doze mode is to conserve power (especially when
+ * running on battery), the dream should not wake the CPU very often or keep it
+ * awake for very long.
+ * </p><p>
+ * It is a good idea to call this method some time after the dream's entry animation
+ * has completed and the dream is ready to doze. It is important to completely
+ * finish all of the work needed before dozing since the application processor may
+ * be suspended at any moment once this method is called unless other wake locks
+ * are being held.
+ * </p><p>
+ * Call {@link #stopDozing} or {@link #finish} to stop dozing.
+ * </p>
+ *
+ * @see #stopDozing
+ * @hide experimental
+ */
+ public void startDozing() {
+ if (mCanDoze && !mDozing) {
+ mDozing = true;
+ try {
+ mSandman.startDozing(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ }
+
+ /**
+ * Stops dozing, returns to active dreaming.
+ * <p>
+ * This method reverses the effect of {@link #startDozing}. From this moment onward,
+ * the application processor will be kept awake as long as the dream is running
+ * or until the dream starts dozing again.
+ * </p>
+ *
+ * @see #startDozing
+ * @hide experimental
+ */
+ public void stopDozing() {
+ if (mDozing) {
+ mDozing = false;
+ try {
+ mSandman.stopDozing(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ }
+
+ /**
+ * Returns true if the dream will allow the system to enter a low-power state while
+ * it is running without actually turning off the screen. Defaults to false,
+ * keeping the application processor awake while the dream is running.
+ *
+ * @return True if the dream is dozing.
+ *
+ * @see #setDozing(boolean)
+ * @hide experimental
+ */
+ public boolean isDozing() {
+ return mDozing;
+ }
+
+ /**
+ * Gets an object that may be used to access low-level hardware features that a
+ * dream may use to provide a richer user experience while dozing.
+ *
+ * @return An instance of {@link DozeHardware} or null if this device does not offer
+ * hardware support for dozing.
+ *
+ * @hide experimental
+ */
+ public DozeHardware getDozeHardware() {
+ if (mCanDoze && mDozeHardware == null) {
+ try {
+ IDozeHardware hardware = mSandman.getDozeHardware(mWindowToken);
+ if (hardware != null) {
+ mDozeHardware = new DozeHardware(hardware);
+ }
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ }
+ return mDozeHardware;
+ }
+
+ /**
* Called when this Dream is constructed.
*/
@Override
@@ -536,7 +666,11 @@
}
/**
- * Stops the dream, detaches from the window, and wakes up.
+ * Stops the dream and detaches from the window.
+ * <p>
+ * When the dream ends, the system will be allowed to go to sleep fully unless there
+ * is a reason for it to be awake such as recent user activity or wake locks being held.
+ * </p>
*/
public final void finish() {
if (mDebug) Slog.v(TAG, "finish()");
@@ -557,10 +691,6 @@
// end public api
- private void loadSandman() {
- mSandman = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
- }
-
/**
* Called by DreamController.stopDream() when the Dream is about to be unbound and destroyed.
*
@@ -572,23 +702,16 @@
return;
}
- try {
- onDreamingStopped();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStopped()", t);
- // we were going to stop anyway
- }
+ if (mDebug) Slog.v(TAG, "detach(): Calling onDreamingStopped()");
+ onDreamingStopped();
if (mDebug) Slog.v(TAG, "detach(): Removing window from window manager");
- try {
- // force our window to be removed synchronously
- mWindowManager.removeViewImmediate(mWindow.getDecorView());
- // the following will print a log message if it finds any other leaked windows
- WindowManagerGlobal.getInstance().closeAll(mWindowToken,
- this.getClass().getName(), "Dream");
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed removing window view", t);
- }
+
+ // force our window to be removed synchronously
+ mWindowManager.removeViewImmediate(mWindow.getDecorView());
+ // the following will print a log message if it finds any other leaked windows
+ WindowManagerGlobal.getInstance().closeAll(mWindowToken,
+ this.getClass().getName(), "Dream");
mWindow = null;
mWindowToken = null;
@@ -601,23 +724,30 @@
*
* @param windowToken A window token that will allow a window to be created in the correct layer.
*/
- private final void attach(IBinder windowToken) {
+ private final void attach(IBinder windowToken, boolean canDoze) {
if (mWindowToken != null) {
Slog.e(TAG, "attach() called when already attached with token=" + mWindowToken);
return;
}
+ if (mFinished) {
+ Slog.w(TAG, "attach() called after dream already finished");
+ try {
+ mSandman.finishSelf(windowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
+ return;
+ }
if (mDebug) Slog.v(TAG, "Attached on thread " + Thread.currentThread().getId());
- if (mSandman == null) {
- loadSandman();
- }
mWindowToken = windowToken;
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(0xFF000000));
mWindow.setFormat(PixelFormat.OPAQUE);
+ mCanDoze = canDoze;
if (mDebug) Slog.v(TAG, String.format("Attaching window token: %s to window of type %s",
windowToken, WindowManager.LayoutParams.TYPE_DREAM));
@@ -642,40 +772,25 @@
mWindowManager = mWindow.getWindowManager();
if (mDebug) Slog.v(TAG, "Window added on thread " + Thread.currentThread().getId());
- try {
- applySystemUiVisibilityFlags(
- (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
- View.SYSTEM_UI_FLAG_LOW_PROFILE);
- getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed adding window view", t);
- safelyFinish();
- return;
- }
+ applySystemUiVisibilityFlags(
+ (mLowProfile ? View.SYSTEM_UI_FLAG_LOW_PROFILE : 0),
+ View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ getWindowManager().addView(mWindow.getDecorView(), mWindow.getAttributes());
// start it up
mHandler.post(new Runnable() {
@Override
public void run() {
- try {
- onDreamingStarted();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in onDreamingStarted()", t);
- safelyFinish();
- }
+ if (mDebug) Slog.v(TAG, "Calling onDreamingStarted()");
+ onDreamingStarted();
}
});
}
private void safelyFinish() {
if (mDebug) Slog.v(TAG, "safelyFinish()");
- try {
- finish();
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in safelyFinish()", t);
- finishInternal();
- return;
- }
+
+ finish();
if (!mFinished) {
Slog.w(TAG, "Bad dream, did not call super.finish()");
@@ -685,19 +800,21 @@
private void finishInternal() {
if (mDebug) Slog.v(TAG, "finishInternal() mFinished = " + mFinished);
- if (mFinished) return;
- try {
+
+ if (!mFinished) {
mFinished = true;
- if (mSandman != null) {
- mSandman.finishSelf(mWindowToken);
+ if (mWindowToken == null) {
+ Slog.w(TAG, "Finish was called before the dream was attached.");
} else {
- Slog.w(TAG, "No dream manager found");
+ try {
+ mSandman.finishSelf(mWindowToken);
+ } catch (RemoteException ex) {
+ // system server died
+ }
}
- stopSelf(); // if launched via any other means
- } catch (Throwable t) {
- Slog.w(TAG, "Crashed in finishInternal()", t);
+ stopSelf(); // if launched via any other means
}
}
@@ -732,32 +849,39 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- super.dump(fd, pw, args);
-
- pw.print(TAG + ": ");
- if (mWindowToken == null) {
- pw.println("stopped");
- } else {
- pw.println("running (token=" + mWindowToken + ")");
- }
- pw.println(" window: " + mWindow);
- pw.print(" flags:");
- if (isInteractive()) pw.print(" interactive");
- if (isLowProfile()) pw.print(" lowprofile");
- if (isFullscreen()) pw.print(" fullscreen");
- if (isScreenBright()) pw.print(" bright");
- pw.println();
+ DumpUtils.dumpAsync(mHandler, new Dump() {
+ @Override
+ public void dump(PrintWriter pw) {
+ pw.print(TAG + ": ");
+ if (mWindowToken == null) {
+ pw.println("stopped");
+ } else {
+ pw.println("running (token=" + mWindowToken + ")");
+ }
+ pw.println(" window: " + mWindow);
+ pw.print(" flags:");
+ if (isInteractive()) pw.print(" interactive");
+ if (isLowProfile()) pw.print(" lowprofile");
+ if (isFullscreen()) pw.print(" fullscreen");
+ if (isScreenBright()) pw.print(" bright");
+ if (isDozing()) pw.print(" dozing");
+ pw.println();
+ }
+ }, pw, 1000);
}
- private class DreamServiceWrapper extends IDreamService.Stub {
- public void attach(final IBinder windowToken) {
+ private final class DreamServiceWrapper extends IDreamService.Stub {
+ @Override
+ public void attach(final IBinder windowToken, final boolean canDoze) {
mHandler.post(new Runnable() {
@Override
public void run() {
- DreamService.this.attach(windowToken);
+ DreamService.this.attach(windowToken, canDoze);
}
});
}
+
+ @Override
public void detach() {
mHandler.post(new Runnable() {
@Override
diff --git a/core/java/android/service/dreams/IDozeHardware.aidl b/core/java/android/service/dreams/IDozeHardware.aidl
new file mode 100644
index 0000000..f5a657b
--- /dev/null
+++ b/core/java/android/service/dreams/IDozeHardware.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.dreams;
+
+/**
+ * @hide
+ */
+interface IDozeHardware {
+ byte[] sendMessage(String msg, in byte[] arg);
+}
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c1b390..2718e316 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -16,10 +16,11 @@
package android.service.dreams;
+import android.content.ComponentName;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
-import android.content.ComponentName;
import android.os.IBinder;
+import android.service.dreams.IDozeHardware;
/** @hide */
interface IDreamManager {
@@ -31,4 +32,7 @@
void testDream(in ComponentName componentName);
boolean isDreaming();
void finishSelf(in IBinder token);
+ void startDozing(in IBinder token);
+ void stopDozing(in IBinder token);
+ IDozeHardware getDozeHardware(in IBinder token);
}
\ No newline at end of file
diff --git a/core/java/android/service/dreams/IDreamService.aidl b/core/java/android/service/dreams/IDreamService.aidl
index 99dc0b7..bd58f1d 100644
--- a/core/java/android/service/dreams/IDreamService.aidl
+++ b/core/java/android/service/dreams/IDreamService.aidl
@@ -20,6 +20,6 @@
* @hide
*/
oneway interface IDreamService {
- void attach(IBinder windowToken);
+ void attach(IBinder windowToken, boolean canDoze);
void detach();
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 2e0e59b..cf862b8 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -112,6 +112,7 @@
* {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
*/
public final void cancelNotification(String pkg, String tag, int id) {
+ if (!isBound()) return;
try {
getNotificationInterface().cancelNotificationFromListener(mWrapper, pkg, tag, id);
} catch (android.os.RemoteException ex) {
@@ -131,6 +132,7 @@
* {@see #cancelNotification(String, String, int)}
*/
public final void cancelAllNotifications() {
+ if (!isBound()) return;
try {
getNotificationInterface().cancelAllNotificationsFromListener(mWrapper);
} catch (android.os.RemoteException ex) {
@@ -145,6 +147,7 @@
* @return An array of active notifications.
*/
public StatusBarNotification[] getActiveNotifications() {
+ if (!isBound()) return null;
try {
return getNotificationInterface().getActiveNotificationsFromListener(mWrapper);
} catch (android.os.RemoteException ex) {
@@ -161,6 +164,14 @@
return mWrapper;
}
+ private boolean isBound() {
+ if (mWrapper == null) {
+ Log.w(TAG, "Notification listener service not yet bound.");
+ return false;
+ }
+ return true;
+ }
+
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 34274a6..b55cd6a 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -29,6 +29,7 @@
*/
public class SpannableStringBuilder implements CharSequence, GetChars, Spannable, Editable,
Appendable, GraphicsOperations {
+ private final static String TAG = "SpannableStringBuilder";
/**
* Create a new SpannableStringBuilder with empty contents
*/
@@ -436,10 +437,26 @@
}
// Documentation from interface
- public SpannableStringBuilder replace(final int start, final int end,
+ public SpannableStringBuilder replace(int start, int end,
CharSequence tb, int tbstart, int tbend) {
checkRange("replace", start, end);
+ // Sanity check
+ if (start > end) {
+ Log.w(TAG, "Bad arguments to #replace : "
+ + "start = " + start + ", end = " + end);
+ final int tmp = start;
+ start = end;
+ end = tmp;
+ }
+ if (tbstart > tbend) {
+ Log.w(TAG, "Bad arguments to #replace : "
+ + "tbstart = " + tbstart + ", tbend = " + tbend);
+ final int tmp = tbstart;
+ tbstart = tbend;
+ tbend = tmp;
+ }
+
int filtercount = mFilters.length;
for (int i = 0; i < filtercount; i++) {
CharSequence repl = mFilters[i].filter(tb, tbstart, tbend, this, start, end);
@@ -613,8 +630,9 @@
// 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
if (flagsStart == POINT && flagsEnd == MARK && start == end) {
- if (send) Log.e("SpannableStringBuilder",
- "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+ if (send) {
+ Log.e(TAG, "SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length");
+ }
// Silently ignore invalid spans when they are created from this class.
// This avoids the duplication of the above test code before all the
// calls to setSpan that are done in this class
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index f2a86c9..7d1c6c4 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -546,6 +546,9 @@
public void skipValue() throws IOException {
skipping = true;
try {
+ if (!hasNext() || peek() == JsonToken.END_DOCUMENT) {
+ throw new IllegalStateException("No element left to skip");
+ }
int count = 0;
do {
JsonToken token = advance();
diff --git a/core/java/android/util/LruCache.java b/core/java/android/util/LruCache.java
index dd504c1..4015488 100644
--- a/core/java/android/util/LruCache.java
+++ b/core/java/android/util/LruCache.java
@@ -87,9 +87,8 @@
/**
* Sets the size of the cache.
- * @param maxSize The new maximum size.
*
- * @hide
+ * @param maxSize The new maximum size.
*/
public void resize(int maxSize) {
if (maxSize <= 0) {
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index 9aecbea..dfc74ea 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -484,9 +484,9 @@
*
* If set to true, camera distance will be ignored. Defaults to false.
*/
- public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+ public void setUsesGlobalCamera(boolean usesGlobalCamera) {
if (hasNativeDisplayList()) {
- nSetSharesGlobalCamera(mFinalizer.mNativeDisplayList, sharesGlobalCamera);
+ nSetUsesGlobalCamera(mFinalizer.mNativeDisplayList, usesGlobalCamera);
}
}
@@ -1116,7 +1116,7 @@
private static native void nSetOutline(long displayList, long nativePath);
private static native void nSetClipToOutline(long displayList, boolean clipToOutline);
private static native void nSetCastsShadow(long displayList, boolean castsShadow);
- private static native void nSetSharesGlobalCamera(long displayList, boolean sharesGlobalCamera);
+ private static native void nSetUsesGlobalCamera(long displayList, boolean usesGlobalCamera);
private static native void nSetAlpha(long displayList, float alpha);
private static native void nSetHasOverlappingRendering(long displayList,
boolean hasOverlappingRendering);
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 2ed0cba..a08d83a 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -351,11 +351,11 @@
// Atlas
///////////////////////////////////////////////////////////////////////////
- static void initAtlas(GraphicBuffer buffer, int[] map) {
+ static void initAtlas(GraphicBuffer buffer, long[] map) {
nInitAtlas(buffer, map, map.length);
}
- private static native void nInitAtlas(GraphicBuffer buffer, int[] map, int count);
+ private static native void nInitAtlas(GraphicBuffer buffer, long[] map, int count);
///////////////////////////////////////////////////////////////////////////
// Display list
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 40ad72c..4c92e950 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -271,7 +271,7 @@
if (atlas.isCompatible(android.os.Process.myPpid())) {
GraphicBuffer buffer = atlas.getBuffer();
if (buffer != null) {
- int[] map = atlas.getMap();
+ long[] map = atlas.getMap();
if (map != null) {
GLES20Canvas.initAtlas(buffer, map);
}
@@ -477,17 +477,22 @@
@Override
void flushLayerUpdates() {
- mGlCanvas.flushLayerUpdates();
+ if (validate()) {
+ flushLayerChanges();
+ mGlCanvas.flushLayerUpdates();
+ }
}
@Override
HardwareLayer createTextureLayer() {
+ validate();
return HardwareLayer.createTextureLayer(this);
}
@Override
public HardwareLayer createDisplayListLayer(int width, int height) {
- return HardwareLayer.createRenderLayer(this, width, height);
+ validate();
+ return HardwareLayer.createDisplayListLayer(this, width, height);
}
@Override
@@ -495,9 +500,20 @@
mAttachedLayers.add(hardwareLayer);
}
+ boolean hasContext() {
+ return sEgl != null && mEglContext != null
+ && mEglContext.equals(sEgl.eglGetCurrentContext());
+ }
+
@Override
void onLayerDestroyed(HardwareLayer layer) {
- mGlCanvas.cancelLayerUpdate(layer);
+ if (mGlCanvas != null) {
+ mGlCanvas.cancelLayerUpdate(layer);
+ }
+ if (hasContext()) {
+ long backingLayer = layer.detachBackingLayer();
+ nDestroyLayer(backingLayer);
+ }
mAttachedLayers.remove(layer);
}
@@ -508,6 +524,9 @@
@Override
boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
+ if (!validate()) {
+ throw new IllegalStateException("Could not acquire hardware rendering context");
+ }
layer.flushChanges();
return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
}
@@ -536,35 +555,6 @@
}
@Override
- void destroyLayers(final View view) {
- if (view != null) {
- safelyRun(new Runnable() {
- @Override
- public void run() {
- if (mCanvas != null) {
- mCanvas.clearLayerUpdates();
- }
- destroyHardwareLayer(view);
- GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
- }
- });
- }
- }
-
- private static void destroyHardwareLayer(View view) {
- view.destroyLayer(true);
-
- if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup) view;
-
- int count = group.getChildCount();
- for (int i = 0; i < count; i++) {
- destroyHardwareLayer(group.getChildAt(i));
- }
- }
- }
-
- @Override
void destroyHardwareResources(final View view) {
if (view != null) {
safelyRun(new Runnable() {
@@ -1067,7 +1057,6 @@
return true;
}
- @Override
boolean validate() {
return checkRenderContext() != SURFACE_STATE_ERROR;
}
@@ -1470,6 +1459,8 @@
*/
static native boolean isBackBufferPreserved();
+ static native void nDestroyLayer(long layerPtr);
+
class DrawPerformanceDataProvider extends GraphDataProvider {
private final int mGraphType;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 9bbcf7c..8900d23 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -33,7 +33,7 @@
*/
final class HardwareLayer {
private static final int LAYER_TYPE_TEXTURE = 1;
- private static final int LAYER_TYPE_RENDER = 2;
+ private static final int LAYER_TYPE_DISPLAY_LIST = 2;
private HardwareRenderer mRenderer;
private Finalizer mFinalizer;
@@ -66,8 +66,7 @@
* @see View#setLayerPaint(android.graphics.Paint)
*/
public void setLayerPaint(Paint paint) {
- nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
- paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
+ nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint);
}
/**
@@ -99,6 +98,10 @@
doDestroyLayerUpdater();
}
+ public long getDeferredLayerUpdater() {
+ return mFinalizer.mDeferredUpdater;
+ }
+
/**
* Destroys the deferred layer updater but not the backing layer. The
* backing layer is instead returned and is the caller's responsibility
@@ -120,7 +123,7 @@
}
public DisplayList startRecording() {
- assertType(LAYER_TYPE_RENDER);
+ assertType(LAYER_TYPE_DISPLAY_LIST);
if (mDisplayList == null) {
mDisplayList = DisplayList.create("HardwareLayer");
@@ -172,9 +175,17 @@
/**
* Indicates that this layer has lost its texture.
*/
- public void onTextureDestroyed() {
+ public void detachSurfaceTexture(final SurfaceTexture surface) {
assertType(LAYER_TYPE_TEXTURE);
- nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+ mRenderer.safelyRun(new Runnable() {
+ @Override
+ public void run() {
+ surface.detachFromGLContext();
+ // SurfaceTexture owns the texture name and detachFromGLContext
+ // should have deleted it
+ nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+ }
+ });
}
/**
@@ -226,12 +237,20 @@
return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
}
+ static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
+ return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
+ }
+
/**
* This should only be used by HardwareRenderer! Do not call directly
*/
- static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+ static HardwareLayer createDisplayListLayer(HardwareRenderer renderer,
int width, int height) {
- return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
+ return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST);
+ }
+
+ static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
+ return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
}
/** This also creates the underlying layer */
@@ -250,7 +269,7 @@
private static native void nDestroyLayerUpdater(long layerUpdater);
private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
- private static native void nSetLayerPaint(long layerUpdater, long paint, long colorFilter);
+ private static native void nSetLayerPaint(long layerUpdater, long paint);
private static native void nSetTransform(long layerUpdater, long matrix);
private static native void nSetSurfaceTexture(long layerUpdater,
SurfaceTexture surface, boolean isAlreadyAttached);
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 93cc9d1..7a943f0 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,13 +234,6 @@
abstract void updateSurface(Surface surface) throws OutOfResourcesException;
/**
- * Destroys the layers used by the specified view hierarchy.
- *
- * @param view The root of the view hierarchy
- */
- abstract void destroyLayers(View view);
-
- /**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
*
@@ -257,15 +250,6 @@
abstract void invalidate(Surface surface);
/**
- * This method should be invoked to ensure the hardware renderer is in
- * valid state (for instance, to ensure the correct EGL context is bound
- * to the current thread.)
- *
- * @return true if the renderer is now valid, false otherwise
- */
- abstract boolean validate();
-
- /**
* This method ensures the hardware renderer is in a valid state
* before executing the specified action.
*
diff --git a/core/java/android/view/IAssetAtlas.aidl b/core/java/android/view/IAssetAtlas.aidl
index 5f1e238..edce059 100644
--- a/core/java/android/view/IAssetAtlas.aidl
+++ b/core/java/android/view/IAssetAtlas.aidl
@@ -45,10 +45,10 @@
* if the atlas is not available yet.
*
* Each bitmap is represented by several entries in the array:
- * int0: SkBitmap*, the native bitmap object
- * int1: x position
- * int2: y position
- * int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+ * long0: SkBitmap*, the native bitmap object
+ * long1: x position
+ * long2: y position
+ * long3: rotated, 1 if the bitmap must be rotated, 0 otherwise
*/
- int[] getMap();
+ long[] getMap();
}
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 30b1e52..7e745d8 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1158,25 +1158,25 @@
* This mask is set if the device woke because of this key event.
*/
public static final int FLAG_WOKE_HERE = 0x1;
-
+
/**
* This mask is set if the key event was generated by a software keyboard.
*/
public static final int FLAG_SOFT_KEYBOARD = 0x2;
-
+
/**
* This mask is set if we don't want the key event to cause us to leave
* touch mode.
*/
public static final int FLAG_KEEP_TOUCH_MODE = 0x4;
-
+
/**
* This mask is set if an event was known to come from a trusted part
* of the system. That is, the event is known to come from the user,
* and could not have been spoofed by a third party component.
*/
public static final int FLAG_FROM_SYSTEM = 0x8;
-
+
/**
* This mask is used for compatibility, to identify enter keys that are
* coming from an IME whose enter key has been auto-labelled "next" or
@@ -1185,7 +1185,7 @@
* receiving them.
*/
public static final int FLAG_EDITOR_ACTION = 0x10;
-
+
/**
* When associated with up key events, this indicates that the key press
* has been canceled. Typically this is used with virtual touch screen
@@ -1194,29 +1194,29 @@
* event and should not perform the action normally associated with the
* key. Note that for this to work, the application can not perform an
* action for a key until it receives an up or the long press timeout has
- * expired.
+ * expired.
*/
public static final int FLAG_CANCELED = 0x20;
-
+
/**
* This key event was generated by a virtual (on-screen) hard key area.
* Typically this is an area of the touchscreen, outside of the regular
* display, dedicated to "hardware" buttons.
*/
public static final int FLAG_VIRTUAL_HARD_KEY = 0x40;
-
+
/**
* This flag is set for the first key repeat that occurs after the
* long press timeout.
*/
public static final int FLAG_LONG_PRESS = 0x80;
-
+
/**
* Set when a key event has {@link #FLAG_CANCELED} set because a long
- * press action was executed while it was down.
+ * press action was executed while it was down.
*/
public static final int FLAG_CANCELED_LONG_PRESS = 0x100;
-
+
/**
* Set for {@link #ACTION_UP} when this event's key code is still being
* tracked from its initial down. That is, somebody requested that tracking
@@ -1273,7 +1273,7 @@
public static int getDeadChar(int accent, int c) {
return KeyCharacterMap.getDeadChar(accent, c);
}
-
+
static final boolean DEBUG = false;
static final String TAG = "KeyEvent";
@@ -1303,10 +1303,10 @@
* KeyEvent.startTracking()} to have the framework track the event
* through its {@link #onKeyUp(int, KeyEvent)} and also call your
* {@link #onKeyLongPress(int, KeyEvent)} if it occurs.
- *
+ *
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
- *
+ *
* @return If you handled the event, return true. If you want to allow
* the event to be handled by the next receiver, return false.
*/
@@ -1319,10 +1319,10 @@
* order to receive this callback, someone in the event change
* <em>must</em> return true from {@link #onKeyDown} <em>and</em>
* call {@link KeyEvent#startTracking()} on the event.
- *
+ *
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
- *
+ *
* @return If you handled the event, return true. If you want to allow
* the event to be handled by the next receiver, return false.
*/
@@ -1330,10 +1330,10 @@
/**
* Called when a key up event has occurred.
- *
+ *
* @param keyCode The value in event.getKeyCode().
* @param event Description of the key event.
- *
+ *
* @return If you handled the event, return true. If you want to allow
* the event to be handled by the next receiver, return false.
*/
@@ -1342,11 +1342,11 @@
/**
* Called when multiple down/up pairs of the same key have occurred
* in a row.
- *
+ *
* @param keyCode The value in event.getKeyCode().
* @param count Number of pairs as returned by event.getRepeatCount().
* @param event Description of the key event.
- *
+ *
* @return If you handled the event, return true. If you want to allow
* the event to be handled by the next receiver, return false.
*/
@@ -1362,7 +1362,7 @@
/**
* Create a new key event.
- *
+ *
* @param action Action code: either {@link #ACTION_DOWN},
* {@link #ACTION_UP}, or {@link #ACTION_MULTIPLE}.
* @param code The key code.
@@ -1376,7 +1376,7 @@
/**
* Create a new key event.
- *
+ *
* @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
* at which this key code originally went down.
* @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
@@ -1399,7 +1399,7 @@
/**
* Create a new key event.
- *
+ *
* @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
* at which this key code originally went down.
* @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
@@ -1424,7 +1424,7 @@
/**
* Create a new key event.
- *
+ *
* @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
* at which this key code originally went down.
* @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
@@ -1453,7 +1453,7 @@
/**
* Create a new key event.
- *
+ *
* @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
* at which this key code originally went down.
* @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
@@ -1484,7 +1484,7 @@
/**
* Create a new key event.
- *
+ *
* @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
* at which this key code originally went down.
* @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
@@ -1520,7 +1520,7 @@
* action, repeat count and source will automatically be set to
* {@link #KEYCODE_UNKNOWN}, {@link #ACTION_MULTIPLE}, 0, and
* {@link InputDevice#SOURCE_KEYBOARD} for you.
- *
+ *
* @param time The time (in {@link android.os.SystemClock#uptimeMillis})
* at which this event occured.
* @param characters The string of characters.
@@ -1558,10 +1558,10 @@
/**
* Copy an existing key event, modifying its time and repeat count.
- *
+ *
* @deprecated Use {@link #changeTimeRepeat(KeyEvent, long, int)}
* instead.
- *
+ *
* @param origEvent The existing event to be copied.
* @param eventTime The new event time
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
@@ -1677,7 +1677,7 @@
/**
* Create a new key event that is the same as the given one, but whose
* event time and repeat count are replaced with the given value.
- *
+ *
* @param event The existing event to be copied. This is not modified.
* @param eventTime The new event time
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
@@ -1687,11 +1687,11 @@
int newRepeat) {
return new KeyEvent(event, eventTime, newRepeat);
}
-
+
/**
* Create a new key event that is the same as the given one, but whose
* event time and repeat count are replaced with the given value.
- *
+ *
* @param event The existing event to be copied. This is not modified.
* @param eventTime The new event time
* (in {@link android.os.SystemClock#uptimeMillis}) of the event.
@@ -1707,10 +1707,10 @@
ret.mFlags = newFlags;
return ret;
}
-
+
/**
* Copy an existing key event, modifying its action.
- *
+ *
* @param origEvent The existing event to be copied.
* @param action The new action code of the event.
*/
@@ -1732,18 +1732,18 @@
/**
* Create a new key event that is the same as the given one, but whose
* action is replaced with the given value.
- *
+ *
* @param event The existing event to be copied. This is not modified.
* @param action The new action code of the event.
*/
public static KeyEvent changeAction(KeyEvent event, int action) {
return new KeyEvent(event, action);
}
-
+
/**
* Create a new key event that is the same as the given one, but whose
* flags are replaced with the given value.
- *
+ *
* @param event The existing event to be copied. This is not modified.
* @param flags The new flags constant.
*/
@@ -1768,7 +1768,7 @@
/**
* Don't use in new code, instead explicitly check
* {@link #getAction()}.
- *
+ *
* @return If the action is ACTION_DOWN, returns true; else false.
*
* @deprecated
@@ -1780,7 +1780,7 @@
/**
* Is this a system key? System keys can not be used for menu shortcuts.
- *
+ *
* TODO: this information should come from a table somewhere.
* TODO: should the dpad keys be here? arguably, because they also shouldn't be menu shortcuts
*/
@@ -1849,6 +1849,30 @@
}
}
+ /**
+ * Whether this key is a media key, which can be send to apps that are
+ * interested in media key events.
+ *
+ * @hide
+ */
+ public static final boolean isMediaKey(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ return true;
+ }
+ return false;
+ }
+
/** {@inheritDoc} */
@Override
public final int getDeviceId() {
@@ -2318,7 +2342,7 @@
/**
* Retrieve the action of this key event. May be either
* {@link #ACTION_DOWN}, {@link #ACTION_UP}, or {@link #ACTION_MULTIPLE}.
- *
+ *
* @return The event action: ACTION_DOWN, ACTION_UP, or ACTION_MULTIPLE.
*/
public final int getAction() {
@@ -2332,7 +2356,7 @@
public final boolean isCanceled() {
return (mFlags&FLAG_CANCELED) != 0;
}
-
+
/**
* Call this during {@link Callback#onKeyDown} to have the system track
* the key through its final up (possibly including a long press). Note
@@ -2343,7 +2367,7 @@
public final void startTracking() {
mFlags |= FLAG_START_TRACKING;
}
-
+
/**
* For {@link #ACTION_UP} events, indicates that the event is still being
* tracked from its initial down event as per
@@ -2352,7 +2376,7 @@
public final boolean isTracking() {
return (mFlags&FLAG_TRACKING) != 0;
}
-
+
/**
* For {@link #ACTION_DOWN} events, indicates that the event has been
* canceled as per {@link #FLAG_LONG_PRESS}.
@@ -2360,11 +2384,11 @@
public final boolean isLongPress() {
return (mFlags&FLAG_LONG_PRESS) != 0;
}
-
+
/**
* Retrieve the key code of the key event. This is the physical key that
* was pressed, <em>not</em> the Unicode character.
- *
+ *
* @return The key code of the event.
*/
public final int getKeyCode() {
@@ -2375,14 +2399,14 @@
* For the special case of a {@link #ACTION_MULTIPLE} event with key
* code of {@link #KEYCODE_UNKNOWN}, this is a raw string of characters
* associated with the event. In all other cases it is null.
- *
+ *
* @return Returns a String of 1 or more characters associated with
* the event.
*/
public final String getCharacters() {
return mCharacters;
}
-
+
/**
* Retrieve the hardware key id of this key event. These values are not
* reliable and vary from device to device.
@@ -2399,7 +2423,7 @@
* events, this is the number of times the key has repeated with the first
* down starting at 0 and counting up from there. For multiple key
* events, this is the number of down/up pairs that have occurred.
- *
+ *
* @return The number of times the key has repeated.
*/
public final int getRepeatCount() {
@@ -2413,7 +2437,7 @@
* Note that when chording keys, this value is the down time of the
* most recently pressed key, which may <em>not</em> be the same physical
* key of this event.
- *
+ *
* @return Returns the most recent key down time, in the
* {@link android.os.SystemClock#uptimeMillis} time base
*/
@@ -2425,7 +2449,7 @@
* Retrieve the time this event occurred,
* in the {@link android.os.SystemClock#uptimeMillis} time base.
*
- * @return Returns the time this event occurred,
+ * @return Returns the time this event occurred,
* in the {@link android.os.SystemClock#uptimeMillis} time base.
*/
@Override
@@ -2454,7 +2478,7 @@
/**
* Renamed to {@link #getDeviceId}.
- *
+ *
* @hide
* @deprecated use {@link #getDeviceId()} instead.
*/
@@ -2486,7 +2510,7 @@
public char getDisplayLabel() {
return getKeyCharacterMap().getDisplayLabel(mKeyCode);
}
-
+
/**
* Gets the Unicode character generated by the specified key and meta
* key state combination.
@@ -2509,7 +2533,7 @@
public int getUnicodeChar() {
return getUnicodeChar(mMetaState);
}
-
+
/**
* Gets the Unicode character generated by the specified key and meta
* key state combination.
@@ -2533,7 +2557,7 @@
public int getUnicodeChar(int metaState) {
return getKeyCharacterMap().get(mKeyCode, metaState);
}
-
+
/**
* Get the character conversion data for a given key code.
*
@@ -2548,7 +2572,7 @@
public boolean getKeyData(KeyData results) {
return getKeyCharacterMap().getKeyData(mKeyCode, results);
}
-
+
/**
* Gets the first character in the character array that can be generated
* by the specified key code.
@@ -2563,7 +2587,7 @@
public char getMatch(char[] chars) {
return getMatch(chars, 0);
}
-
+
/**
* Gets the first character in the character array that can be generated
* by the specified key code. If there are multiple choices, prefers
@@ -2576,7 +2600,7 @@
public char getMatch(char[] chars, int metaState) {
return getKeyCharacterMap().getMatch(mKeyCode, chars, metaState);
}
-
+
/**
* Gets the number or symbol associated with the key.
* <p>
@@ -2600,7 +2624,7 @@
public char getNumber() {
return getKeyCharacterMap().getNumber(mKeyCode);
}
-
+
/**
* Returns true if this key produces a glyph.
*
@@ -2609,7 +2633,7 @@
public boolean isPrintingKey() {
return getKeyCharacterMap().isPrintingKey(mKeyCode);
}
-
+
/**
* @deprecated Use {@link #dispatch(Callback, DispatcherState, Object)} instead.
*/
@@ -2617,16 +2641,16 @@
public final boolean dispatch(Callback receiver) {
return dispatch(receiver, null, null);
}
-
+
/**
* Deliver this key event to a {@link Callback} interface. If this is
* an ACTION_MULTIPLE event and it is not handled, then an attempt will
* be made to deliver a single normal event.
- *
+ *
* @param receiver The Callback that will be given the event.
* @param state State information retained across events.
* @param target The target of the dispatch, for use in tracking.
- *
+ *
* @return The return value from the Callback method that was called.
*/
public final boolean dispatch(Callback receiver, DispatcherState state,
@@ -2692,7 +2716,7 @@
int mDownKeyCode;
Object mDownTarget;
SparseIntArray mActiveLongPresses = new SparseIntArray();
-
+
/**
* Reset back to initial state.
*/
@@ -2702,7 +2726,7 @@
mDownTarget = null;
mActiveLongPresses.clear();
}
-
+
/**
* Stop any tracking associated with this target.
*/
@@ -2713,14 +2737,14 @@
mDownTarget = null;
}
}
-
+
/**
* Start tracking the key code associated with the given event. This
* can only be called on a key down. It will allow you to see any
* long press associated with the key, and will result in
* {@link KeyEvent#isTracking} return true on the long press and up
* events.
- *
+ *
* <p>This is only needed if you are directly dispatching events, rather
* than handling them in {@link Callback#onKeyDown}.
*/
@@ -2733,7 +2757,7 @@
mDownKeyCode = event.getKeyCode();
mDownTarget = target;
}
-
+
/**
* Return true if the key event is for a key code that is currently
* being tracked by the dispatcher.
@@ -2741,7 +2765,7 @@
public boolean isTracking(KeyEvent event) {
return mDownKeyCode == event.getKeyCode();
}
-
+
/**
* Keep track of the given event's key code as having performed an
* action with a long press, so no action should occur on the up.
@@ -2751,7 +2775,7 @@
public void performedLongPress(KeyEvent event) {
mActiveLongPresses.put(event.getKeyCode(), 1);
}
-
+
/**
* Handle key up event to stop tracking. This resets the dispatcher state,
* and updates the key event state based on it.
@@ -2906,12 +2930,12 @@
return new KeyEvent[size];
}
};
-
+
/** @hide */
public static KeyEvent createFromParcelBody(Parcel in) {
return new KeyEvent(in);
}
-
+
private KeyEvent(Parcel in) {
mDeviceId = in.readInt();
mSource = in.readInt();
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index aaa8b8c..c4fac46 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -90,6 +90,7 @@
private static final String TAG_INCLUDE = "include";
private static final String TAG_1995 = "blink";
private static final String TAG_REQUEST_FOCUS = "requestFocus";
+ private static final String TAG_TAG = "tag";
private static final int[] ATTRS_THEME = new int[] {
com.android.internal.R.attr.theme };
@@ -778,6 +779,8 @@
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
+ } else if (TAG_TAG.equals(name)) {
+ parseViewTag(parser, parent, attrs);
} else if (TAG_INCLUDE.equals(name)) {
if (parser.getDepth() == 0) {
throw new InflateException("<include /> cannot be the root element");
@@ -797,10 +800,36 @@
if (finishInflate) parent.onFinishInflate();
}
- private void parseRequestFocus(XmlPullParser parser, View parent)
+ /**
+ * Parses a <code><request-focus></code> element and requests focus on
+ * the containing View.
+ */
+ private void parseRequestFocus(XmlPullParser parser, View view)
throws XmlPullParserException, IOException {
int type;
- parent.requestFocus();
+ view.requestFocus();
+ final int currentDepth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
+ // Empty
+ }
+ }
+
+ /**
+ * Parses a <code><tag></code> element and sets a keyed tag on the
+ * containing View.
+ */
+ private void parseViewTag(XmlPullParser parser, View view, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+ int type;
+
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ attrs, com.android.internal.R.styleable.ViewTag);
+ final int key = ta.getResourceId(com.android.internal.R.styleable.ViewTag_id, 0);
+ final CharSequence value = ta.getText(com.android.internal.R.styleable.ViewTag_value);
+ view.setTag(key, value);
+ ta.recycle();
+
final int currentDepth = parser.getDepth();
while (((type = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 97a1f21..5a8d2c8 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -39,9 +39,11 @@
private static native void nativeDestroy(long nativeObject);
private static native Bitmap nativeScreenshot(IBinder displayToken,
- int width, int height, int minLayer, int maxLayer, boolean allLayers);
+ int width, int height, int minLayer, int maxLayer, boolean allLayers,
+ boolean useIdentityTransform);
private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
- int width, int height, int minLayer, int maxLayer, boolean allLayers);
+ int width, int height, int minLayer, int maxLayer, boolean allLayers,
+ boolean useIdentityTransform);
private static native void nativeOpenTransaction();
private static native void nativeCloseTransaction();
@@ -554,10 +556,15 @@
* include in the screenshot.
* @param maxLayer The highest (top-most Z order) surface layer to
* include in the screenshot.
+ * @param useIdentityTransform Replace whatever transformation (rotation,
+ * scaling, translation) the surface layers are currently using with the
+ * identity transformation while taking the screenshot.
*/
public static void screenshot(IBinder display, Surface consumer,
- int width, int height, int minLayer, int maxLayer) {
- screenshot(display, consumer, width, height, minLayer, maxLayer, false);
+ int width, int height, int minLayer, int maxLayer,
+ boolean useIdentityTransform) {
+ screenshot(display, consumer, width, height, minLayer, maxLayer, false,
+ useIdentityTransform);
}
/**
@@ -572,7 +579,7 @@
*/
public static void screenshot(IBinder display, Surface consumer,
int width, int height) {
- screenshot(display, consumer, width, height, 0, 0, true);
+ screenshot(display, consumer, width, height, 0, 0, true, false);
}
/**
@@ -582,7 +589,7 @@
* @param consumer The {@link Surface} to take the screenshot into.
*/
public static void screenshot(IBinder display, Surface consumer) {
- screenshot(display, consumer, 0, 0, 0, 0, true);
+ screenshot(display, consumer, 0, 0, 0, 0, true, false);
}
@@ -602,15 +609,20 @@
* include in the screenshot.
* @param maxLayer The highest (top-most Z order) surface layer to
* include in the screenshot.
+ * @param useIdentityTransform Replace whatever transformation (rotation,
+ * scaling, translation) the surface layers are currently using with the
+ * identity transformation while taking the screenshot.
* @return Returns a Bitmap containing the screen contents, or null
* if an error occurs. Make sure to call Bitmap.recycle() as soon as
* possible, once its content is not needed anymore.
*/
- public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer) {
+ public static Bitmap screenshot(int width, int height, int minLayer, int maxLayer,
+ boolean useIdentityTransform) {
// TODO: should take the display as a parameter
IBinder displayToken = SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
- return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false);
+ return nativeScreenshot(displayToken, width, height, minLayer, maxLayer, false,
+ useIdentityTransform);
}
/**
@@ -629,17 +641,19 @@
// TODO: should take the display as a parameter
IBinder displayToken = SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
- return nativeScreenshot(displayToken, width, height, 0, 0, true);
+ return nativeScreenshot(displayToken, width, height, 0, 0, true, false);
}
private static void screenshot(IBinder display, Surface consumer,
- int width, int height, int minLayer, int maxLayer, boolean allLayers) {
+ int width, int height, int minLayer, int maxLayer, boolean allLayers,
+ boolean useIdentityTransform) {
if (display == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
if (consumer == null) {
throw new IllegalArgumentException("consumer must not be null");
}
- nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers);
+ nativeScreenshot(display, consumer, width, height, minLayer, maxLayer, allLayers,
+ useIdentityTransform);
}
}
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 0dfd94a..3cf5af4 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -24,11 +24,11 @@
*/
public final class SurfaceSession {
// Note: This field is accessed by native code.
- private int mNativeClient; // SurfaceComposerClient*
+ private long mNativeClient; // SurfaceComposerClient*
- private static native int nativeCreate();
- private static native void nativeDestroy(int ptr);
- private static native void nativeKill(int ptr);
+ private static native long nativeCreate();
+ private static native void nativeDestroy(long ptr);
+ private static native void nativeKill(long ptr);
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index e789407..ef0d80d 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -231,26 +231,12 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mLayer != null) {
- boolean success = executeHardwareAction(new Runnable() {
- @Override
- public void run() {
- destroySurface();
- }
- });
-
- if (!success) {
- Log.w(LOG_TAG, "TextureView was not able to destroy its surface: " + this);
- }
- }
+ destroySurface();
}
private void destroySurface() {
if (mLayer != null) {
- mSurface.detachFromGLContext();
- // SurfaceTexture owns the texture name and detachFromGLContext
- // should have deleted it
- mLayer.onTextureDestroyed();
+ mLayer.detachSurfaceTexture(mSurface);
boolean shouldRelease = true;
if (mListener != null) {
@@ -608,14 +594,6 @@
*/
public Bitmap getBitmap(Bitmap bitmap) {
if (bitmap != null && isAvailable()) {
- AttachInfo info = mAttachInfo;
- if (info != null && info.mHardwareRenderer != null &&
- info.mHardwareRenderer.isEnabled()) {
- if (!info.mHardwareRenderer.validate()) {
- throw new IllegalStateException("Could not acquire hardware rendering context");
- }
- }
-
applyUpdate();
applyTransformMatrix();
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1d7e5b2..e8f5e45 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -76,13 +76,7 @@
}
@Override
- void destroyLayers(View view) {
- throw new NoSuchMethodError();
- }
-
- @Override
void destroyHardwareResources(View view) {
- // TODO: canvas.clearLayerUpdates()
destroyResources(view);
// TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
}
@@ -106,12 +100,6 @@
}
@Override
- boolean validate() {
- // TODO Remove users of this API
- return false;
- }
-
- @Override
boolean safelyRun(Runnable action) {
nRunWithGlContext(mNativeProxy, action);
return true;
@@ -150,26 +138,6 @@
return false;
}
- @Override
- void pushLayerUpdate(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- void onLayerCreated(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- void onLayerDestroyed(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- void flushLayerUpdates() {
- throw new NoSuchMethodError();
- }
-
/**
* TODO: Remove
* Temporary hack to allow RenderThreadTest prototype app to trigger
@@ -203,26 +171,6 @@
}
@Override
- HardwareLayer createTextureLayer() {
- throw new NoSuchMethodError();
- }
-
- @Override
- HardwareLayer createDisplayListLayer(int width, int height) {
- throw new NoSuchMethodError();
- }
-
- @Override
- SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
- throw new NoSuchMethodError();
- }
-
- @Override
- boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
- throw new NoSuchMethodError();
- }
-
- @Override
void detachFunctor(long functor) {
nDetachFunctor(mNativeProxy, functor);
}
@@ -233,6 +181,56 @@
}
@Override
+ HardwareLayer createDisplayListLayer(int width, int height) {
+ long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
+ return HardwareLayer.adoptDisplayListLayer(this, layer);
+ }
+
+ @Override
+ HardwareLayer createTextureLayer() {
+ long layer = nCreateTextureLayer(mNativeProxy);
+ return HardwareLayer.adoptTextureLayer(this, layer);
+ }
+
+ @Override
+ SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
+ final SurfaceTexture[] ret = new SurfaceTexture[1];
+ nRunWithGlContext(mNativeProxy, new Runnable() {
+ @Override
+ public void run() {
+ ret[0] = layer.createSurfaceTexture();
+ }
+ });
+ return ret[0];
+ }
+
+ @Override
+ boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
+ return nCopyLayerInto(mNativeProxy,
+ layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+ }
+
+ @Override
+ void pushLayerUpdate(HardwareLayer layer) {
+ // TODO: Remove this, it's not needed outside of GLRenderer
+ }
+
+ @Override
+ void onLayerCreated(HardwareLayer layer) {
+ // TODO: Is this actually useful?
+ }
+
+ @Override
+ void flushLayerUpdates() {
+ // TODO: Figure out what this should do or remove it
+ }
+
+ @Override
+ void onLayerDestroyed(HardwareLayer layer) {
+ nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
+ }
+
+ @Override
void setName(String name) {
}
@@ -261,4 +259,9 @@
private static native void nAttachFunctor(long nativeProxy, long functor);
private static native void nDetachFunctor(long nativeProxy, long functor);
+
+ private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
+ private static native long nCreateTextureLayer(long nativeProxy);
+ private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
+ private static native void nDestroyLayer(long nativeProxy, long layer);
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 393b166..e9082c3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2393,7 +2393,7 @@
* Flag indicating that view will be transformed by the global camera if rotated in 3d, or given
* a non-0 Z translation.
*/
- static final int PFLAG3_SHARES_GLOBAL_CAMERA = 0x200;
+ static final int PFLAG3_USES_GLOBAL_CAMERA = 0x200;
/* End of masks for mPrivateFlags3 */
@@ -4037,6 +4037,11 @@
case R.styleable.View_layerType:
setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null);
break;
+ case R.styleable.View_castsShadow:
+ if (a.getBoolean(attr, false)) {
+ mPrivateFlags3 |= PFLAG3_CASTS_SHADOW;
+ }
+ break;
case R.styleable.View_textDirection:
// Clear any text direction flag already set
mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK;
@@ -6161,7 +6166,7 @@
mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS;
return !dispatchApplyWindowInsets(new WindowInsets(insets)).hasInsets();
} finally {
- mPrivateFlags3 &= PFLAG3_FITTING_SYSTEM_WINDOWS;
+ mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS;
}
} else {
// We're being called from the newer apply insets path.
@@ -10809,9 +10814,20 @@
}
/**
- * @hide
+ * Copies the Outline of the View into the Path parameter.
+ * <p>
+ * If the outline is not set, the parameter Path is set to empty.
+ *
+ * @param outline Path into which View's outline will be copied. Must be non-null.
+ *
+ * @see #setOutline(Path)
+ * @see #getClipToOutline()
+ * @see #setClipToOutline(boolean)
*/
- public final void getOutline(Path outline) {
+ public final void getOutline(@NonNull Path outline) {
+ if (outline == null) {
+ throw new IllegalArgumentException("Path must be non-null");
+ }
if (mOutline == null) {
outline.reset();
} else {
@@ -10820,30 +10836,58 @@
}
/**
- * @hide
+ * Sets the outline of the view, which defines the shape of the shadow it
+ * casts, and can used for clipping.
+ * <p>
+ * If the outline is not set, or {@link Path#isEmpty()}, shadows will be
+ * cast from the bounds of the View, and clipToOutline will be ignored.
+ *
+ * @param outline The new outline of the view. Must be non-null.
+ *
+ * @see #getOutline(Path)
+ * @see #getClipToOutline()
+ * @see #setClipToOutline(boolean)
*/
- public void setOutline(Path path) {
+ public void setOutline(@NonNull Path outline) {
+ if (outline == null) {
+ throw new IllegalArgumentException("Path must be non-null");
+ }
// always copy the path since caller may reuse
if (mOutline == null) {
- mOutline = new Path(path);
+ mOutline = new Path(outline);
} else {
- mOutline.set(path);
+ mOutline.set(outline);
}
if (mDisplayList != null) {
- mDisplayList.setOutline(path);
+ mDisplayList.setOutline(outline);
}
}
/**
- * @hide
+ * Returns whether the outline of the View will be used for clipping.
+ *
+ * @see #getOutline(Path)
+ * @see #setOutline(Path)
*/
public final boolean getClipToOutline() {
return ((mPrivateFlags3 & PFLAG3_CLIP_TO_OUTLINE) != 0);
}
/**
- * @hide
+ * Sets whether the outline of the View will be used for clipping.
+ * <p>
+ * The current implementation of outline clipping uses Canvas#clipPath(),
+ * and thus does not support anti-aliasing, and is expensive in terms of
+ * graphics performance. Therefore, it is strongly recommended that this
+ * property only be set temporarily, as in an animation. For the same
+ * reasons, there is no parallel XML attribute for this property.
+ * <p>
+ * If the outline of the view is not set or is empty, no clipping will be
+ * performed.
+ *
+ * @see #getOutline(Path)
+ * @see #setOutline(Path)
*/
public void setClipToOutline(boolean clipToOutline) {
// TODO : Add a fast invalidation here.
@@ -10860,14 +10904,35 @@
}
/**
- * @hide
+ * Returns whether the View will cast shadows when its
+ * {@link #setTranslationZ(float) z translation} is greater than 0, or it is
+ * rotated in 3D.
+ *
+ * @see #setTranslationZ(float)
+ * @see #setRotationX(float)
+ * @see #setRotationY(float)
+ * @see #setCastsShadow(boolean)
+ * @attr ref android.R.styleable#View_castsShadow
*/
public final boolean getCastsShadow() {
return ((mPrivateFlags3 & PFLAG3_CASTS_SHADOW) != 0);
}
/**
- * @hide
+ * Set to true to enable this View to cast shadows.
+ * <p>
+ * If enabled, and the View has a z translation greater than 0, or is
+ * rotated in 3D, the shadow will be cast onto the current
+ * {@link ViewGroup#setIsolatedZVolume(boolean) isolated Z volume},
+ * at the z = 0 plane.
+ * <p>
+ * The shape of the shadow being cast is defined by the
+ * {@link #setOutline(Path) outline} of the view, or the rectangular bounds
+ * of the view if the outline is not set or is empty.
+ *
+ * @see #setTranslationZ(float)
+ * @see #getCastsShadow()
+ * @attr ref android.R.styleable#View_castsShadow
*/
public void setCastsShadow(boolean castsShadow) {
// TODO : Add a fast invalidation here.
@@ -10884,25 +10949,46 @@
}
/**
+ * Returns whether the View will be transformed by the global camera.
+ *
+ * @see #setUsesGlobalCamera(boolean)
+ *
* @hide
*/
- public final boolean getSharesGlobalCamera() {
- return ((mPrivateFlags3 & PFLAG3_SHARES_GLOBAL_CAMERA) != 0);
+ public final boolean getUsesGlobalCamera() {
+ return ((mPrivateFlags3 & PFLAG3_USES_GLOBAL_CAMERA) != 0);
}
/**
+ * Sets whether the View should be transformed by the global camera.
+ * <p>
+ * If the view has a Z translation or 3D rotation, perspective from the
+ * global camera will be applied. This enables an app to transform multiple
+ * views in 3D with coherent perspective projection among them all.
+ * <p>
+ * Setting this to true will cause {@link #setCameraDistance() camera distance}
+ * to be ignored, as the global camera's position will dictate perspective
+ * transform.
+ * <p>
+ * This should not be used in conjunction with {@link android.graphics.Camera}.
+ *
+ * @see #getUsesGlobalCamera()
+ * @see #setTranslationZ(float)
+ * @see #setRotationX(float)
+ * @see #setRotationY(float)
+ *
* @hide
*/
- public void setSharesGlobalCamera(boolean sharesGlobalCamera) {
+ public void setUsesGlobalCamera(boolean usesGlobalCamera) {
// TODO : Add a fast invalidation here.
- if (getSharesGlobalCamera() != sharesGlobalCamera) {
- if (sharesGlobalCamera) {
- mPrivateFlags3 |= PFLAG3_SHARES_GLOBAL_CAMERA;
+ if (getUsesGlobalCamera() != usesGlobalCamera) {
+ if (usesGlobalCamera) {
+ mPrivateFlags3 |= PFLAG3_USES_GLOBAL_CAMERA;
} else {
- mPrivateFlags3 &= ~PFLAG3_SHARES_GLOBAL_CAMERA;
+ mPrivateFlags3 &= ~PFLAG3_USES_GLOBAL_CAMERA;
}
if (mDisplayList != null) {
- mDisplayList.setSharesGlobalCamera(sharesGlobalCamera);
+ mDisplayList.setUsesGlobalCamera(usesGlobalCamera);
}
}
}
@@ -11361,76 +11447,54 @@
(!(mParent instanceof ViewGroup) ||
!((ViewGroup) mParent).isViewTransitioning(this));
}
+
/**
* Mark the area defined by dirty as needing to be drawn. If the view is
- * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some point
- * in the future. This must be called from a UI thread. To call from a non-UI
- * thread, call {@link #postInvalidate()}.
+ * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some
+ * point in the future.
+ * <p>
+ * This must be called from a UI thread. To call from a non-UI thread, call
+ * {@link #postInvalidate()}.
+ * <p>
+ * <b>WARNING:</b> In API 19 and below, this method may be destructive to
+ * {@code dirty}.
*
- * WARNING: This method is destructive to dirty.
* @param dirty the rectangle representing the bounds of the dirty region
*/
public void invalidate(Rect dirty) {
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
- (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID ||
- (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) {
- mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags |= PFLAG_INVALIDATED;
- mPrivateFlags |= PFLAG_DIRTY;
- final ViewParent p = mParent;
- final AttachInfo ai = mAttachInfo;
- if (p != null && ai != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- final Rect r = ai.mTmpInvalRect;
- r.set(dirty.left - scrollX, dirty.top - scrollY,
- dirty.right - scrollX, dirty.bottom - scrollY);
- mParent.invalidateChild(this, r);
- }
- }
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
+ dirty.right - scrollX, dirty.bottom - scrollY, true, false);
}
/**
- * Mark the area defined by the rect (l,t,r,b) as needing to be drawn.
- * The coordinates of the dirty rect are relative to the view.
- * If the view is visible, {@link #onDraw(android.graphics.Canvas)}
- * will be called at some point in the future. This must be called from
- * a UI thread. To call from a non-UI thread, call {@link #postInvalidate()}.
+ * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The
+ * coordinates of the dirty rect are relative to the view. If the view is
+ * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some
+ * point in the future.
+ * <p>
+ * This must be called from a UI thread. To call from a non-UI thread, call
+ * {@link #postInvalidate()}.
+ *
* @param l the left position of the dirty region
* @param t the top position of the dirty region
* @param r the right position of the dirty region
* @param b the bottom position of the dirty region
*/
public void invalidate(int l, int t, int r, int b) {
- if (skipInvalidate()) {
- return;
- }
- if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
- (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID ||
- (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED) {
- mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
- mPrivateFlags |= PFLAG_INVALIDATED;
- mPrivateFlags |= PFLAG_DIRTY;
- final ViewParent p = mParent;
- final AttachInfo ai = mAttachInfo;
- if (p != null && ai != null && l < r && t < b) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- final Rect tmpr = ai.mTmpInvalRect;
- tmpr.set(l - scrollX, t - scrollY, r - scrollX, b - scrollY);
- p.invalidateChild(this, tmpr);
- }
- }
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false);
}
/**
* Invalidate the whole view. If the view is visible,
* {@link #onDraw(android.graphics.Canvas)} will be called at some point in
- * the future. This must be called from a UI thread. To call from a non-UI thread,
- * call {@link #postInvalidate()}.
+ * the future.
+ * <p>
+ * This must be called from a UI thread. To call from a non-UI thread, call
+ * {@link #postInvalidate()}.
*/
public void invalidate() {
invalidate(true);
@@ -11438,38 +11502,108 @@
/**
* This is where the invalidate() work actually happens. A full invalidate()
- * causes the drawing cache to be invalidated, but this function can be called with
- * invalidateCache set to false to skip that invalidation step for cases that do not
- * need it (for example, a component that remains at the same dimensions with the same
- * content).
+ * causes the drawing cache to be invalidated, but this function can be
+ * called with invalidateCache set to false to skip that invalidation step
+ * for cases that do not need it (for example, a component that remains at
+ * the same dimensions with the same content).
*
- * @param invalidateCache Whether the drawing cache for this view should be invalidated as
- * well. This is usually true for a full invalidate, but may be set to false if the
- * View's contents or dimensions have not changed.
+ * @param invalidateCache Whether the drawing cache for this view should be
+ * invalidated as well. This is usually true for a full
+ * invalidate, but may be set to false if the View's contents or
+ * dimensions have not changed.
*/
void invalidate(boolean invalidateCache) {
+ invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);
+ }
+
+ void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache,
+ boolean fullInvalidate) {
if (skipInvalidate()) {
return;
}
- if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
- (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||
- (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {
- mLastIsOpaque = isOpaque();
- mPrivateFlags &= ~PFLAG_DRAWN;
+
+ if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)
+ || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID)
+ || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED
+ || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
+ if (fullInvalidate) {
+ mLastIsOpaque = isOpaque();
+ mPrivateFlags &= ~PFLAG_DRAWN;
+ }
+
mPrivateFlags |= PFLAG_DIRTY;
+
if (invalidateCache) {
mPrivateFlags |= PFLAG_INVALIDATED;
mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
}
+
+ // Propagate the damage rectangle to the parent view.
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
+ if (p != null && ai != null && l < r && t < b) {
+ final Rect damage = ai.mTmpInvalRect;
+ damage.set(l, t, r, b);
+ p.invalidateChild(this, damage);
+ }
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- // Don't call invalidate -- we don't want to internally scroll
- // our own bounds
- p.invalidateChild(this, r);
+ // Damage the entire projection receiver, if necessary.
+ if (mBackground != null && mBackground.isProjected()) {
+ final View receiver = getProjectionReceiver();
+ if (receiver != null) {
+ receiver.damageInParent();
+ }
+ }
+
+ // Damage the entire IsolatedZVolume recieving this view's shadow.
+ if (getCastsShadow() && getTranslationZ() != 0) {
+ damageIsolatedZVolume();
+ }
+ }
+ }
+
+ /**
+ * @return this view's projection receiver, or {@code null} if none exists
+ */
+ private View getProjectionReceiver() {
+ ViewParent p = getParent();
+ while (p != null && p instanceof View) {
+ final View v = (View) p;
+ if (v.isProjectionReceiver()) {
+ return v;
+ }
+ p = p.getParent();
+ }
+
+ return null;
+ }
+
+ /**
+ * @return whether the view is a projection receiver
+ */
+ private boolean isProjectionReceiver() {
+ return mBackground != null;
+ }
+
+ /**
+ * Damage area of the screen covered by the current isolated Z volume
+ *
+ * This method will guarantee that any changes to shadows cast by a View
+ * are damaged on the screen for future redraw.
+ */
+ private void damageIsolatedZVolume() {
+ final AttachInfo ai = mAttachInfo;
+ if (ai != null) {
+ ViewParent p = getParent();
+ while (p != null) {
+ if (p instanceof ViewGroup) {
+ final ViewGroup vg = (ViewGroup) p;
+ if (vg.hasIsolatedZVolume()) {
+ vg.damageInParent();
+ return;
+ }
+ }
+ p = p.getParent();
}
}
}
@@ -11500,16 +11634,28 @@
}
invalidate(false);
} else {
- final AttachInfo ai = mAttachInfo;
- final ViewParent p = mParent;
- if (p != null && ai != null) {
- final Rect r = ai.mTmpInvalRect;
- r.set(0, 0, mRight - mLeft, mBottom - mTop);
- if (mParent instanceof ViewGroup) {
- ((ViewGroup) mParent).invalidateChildFast(this, r);
- } else {
- mParent.invalidateChild(this, r);
- }
+ damageInParent();
+ }
+ if (invalidateParent && getCastsShadow() && getTranslationZ() != 0) {
+ damageIsolatedZVolume();
+ }
+ }
+
+ /**
+ * Tells the parent view to damage this view's bounds.
+ *
+ * @hide
+ */
+ protected void damageInParent() {
+ final AttachInfo ai = mAttachInfo;
+ final ViewParent p = mParent;
+ if (p != null && ai != null) {
+ final Rect r = ai.mTmpInvalRect;
+ r.set(0, 0, mRight - mLeft, mBottom - mTop);
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).invalidateChildFast(this, r);
+ } else {
+ mParent.invalidateChild(this, r);
}
}
}
@@ -12382,7 +12528,7 @@
}
/**
- * <p>Compute the vertical extent of the horizontal scrollbar's thumb
+ * <p>Compute the vertical extent of the vertical scrollbar's thumb
* within the vertical range. This value is used to compute the length
* of the thumb within the scrollbar's track.</p>
*
@@ -12669,6 +12815,10 @@
if (mDisplayList != null) {
mDisplayList.clearDirty();
}
+
+ if (mBackgroundDisplayList != null) {
+ mBackgroundDisplayList.clearDirty();
+ }
}
/**
@@ -12987,13 +13137,18 @@
private void cleanupDraw() {
if (mAttachInfo != null) {
+ // Ensure the display lists are reset when the view root dies.
if (mDisplayList != null) {
mDisplayList.markDirty();
mAttachInfo.mViewRootImpl.enqueueDisplayList(mDisplayList);
}
+ if (mBackgroundDisplayList != null) {
+ mBackgroundDisplayList.markDirty();
+ mAttachInfo.mViewRootImpl.enqueueDisplayList(mBackgroundDisplayList);
+ }
mAttachInfo.mViewRootImpl.cancelInvalidate(this);
} else {
- // Should never happen
+ // Should never happen.
resetDisplayList();
}
}
@@ -13584,19 +13739,15 @@
switch (mLayerType) {
case LAYER_TYPE_HARDWARE:
- if (attachInfo.mHardwareRenderer != null &&
- attachInfo.mHardwareRenderer.isEnabled() &&
- attachInfo.mHardwareRenderer.validate()) {
- getHardwareLayer();
- // TODO: We need a better way to handle this case
- // If views have registered pre-draw listeners they need
- // to be notified before we build the layer. Those listeners
- // may however rely on other events to happen first so we
- // cannot just invoke them here until they don't cancel the
- // current frame
- if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
- attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
- }
+ getHardwareLayer();
+ // TODO: We need a better way to handle this case
+ // If views have registered pre-draw listeners they need
+ // to be notified before we build the layer. Those listeners
+ // may however rely on other events to happen first so we
+ // cannot just invoke them here until they don't cancel the
+ // current frame
+ if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
+ attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
}
break;
case LAYER_TYPE_SOFTWARE:
@@ -13617,8 +13768,6 @@
return null;
}
- if (!mAttachInfo.mHardwareRenderer.validate()) return null;
-
final int width = mRight - mLeft;
final int height = mBottom - mTop;
@@ -14536,7 +14685,7 @@
displayList.setOutline(mOutline);
displayList.setClipToOutline(getClipToOutline());
displayList.setCastsShadow(getCastsShadow());
- displayList.setSharesGlobalCamera(getSharesGlobalCamera());
+ displayList.setUsesGlobalCamera(getUsesGlobalCamera());
float alpha = 1;
if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags &
ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
@@ -15136,12 +15285,6 @@
}
if (mBackgroundSizeChanged) {
- // We should see the background invalidate itself, but just to be
- // careful we're going to clear the display list and force redraw.
- if (mBackgroundDisplayList != null) {
- mBackgroundDisplayList.clear();
- }
-
background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
mBackgroundSizeChanged = false;
}
@@ -15189,10 +15332,6 @@
* @return A valid display list for the specified drawable
*/
private static DisplayList getDrawableDisplayList(Drawable drawable, DisplayList displayList) {
- if (displayList != null && displayList.isValid()) {
- return displayList;
- }
-
if (displayList == null) {
displayList = DisplayList.create(drawable.getClass().getName());
}
@@ -15556,11 +15695,6 @@
@Override
public void invalidateDrawable(Drawable drawable) {
if (verifyDrawable(drawable)) {
- if (drawable == mBackground && mBackgroundDisplayList != null) {
- // We'll need to redraw the display list.
- mBackgroundDisplayList.clear();
- }
-
final Rect dirty = drawable.getDirtyBounds();
final int scrollX = mScrollX;
final int scrollY = mScrollY;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index c3bf533..9cd3c9d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3176,6 +3176,7 @@
* @return True if the group should be an isolated Z volume with its own Z
* ordering space, false if its decendents should inhabit the
* inherited Z ordering volume.
+ * @attr ref android.R.styleable#ViewGroup_isolatedZVolume
*/
public void setIsolatedZVolume(boolean isolateZVolume) {
boolean previousValue = (mGroupFlags & FLAG_ISOLATED_Z_VOLUME) != 0;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ef69948..2b32d70 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -232,8 +232,6 @@
InputStage mFirstInputStage;
InputStage mFirstPostImeInputStage;
- boolean mFlipControllerFallbackKeys;
-
boolean mWindowAttributesChanged = false;
int mWindowAttributesChangesFlag = 0;
@@ -266,10 +264,10 @@
int mScrollY;
int mCurScrollY;
Scroller mScroller;
-// HardwareLayer mResizeBuffer;
-// long mResizeBufferStartTime;
-// int mResizeBufferDuration;
-// static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
+ HardwareLayer mResizeBuffer;
+ long mResizeBufferStartTime;
+ int mResizeBufferDuration;
+ static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
private ArrayList<LayoutTransition> mPendingTransitions;
final ViewConfiguration mViewConfiguration;
@@ -370,8 +368,6 @@
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
mChoreographer = Choreographer.getInstance();
- mFlipControllerFallbackKeys =
- context.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mAttachInfo.mScreenOn = powerManager.isScreenOn();
@@ -635,16 +631,25 @@
}
} else {
invalidateDisplayLists();
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+ destroyHardwareLayer(mView);
+ }
+ }
+
+ private static void destroyHardwareLayer(View view) {
+ view.destroyLayer(true);
+
+ if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup) view;
+
+ int count = group.getChildCount();
+ for (int i = 0; i < count; i++) {
+ destroyHardwareLayer(group.getChildAt(i));
}
}
}
void flushHardwareLayerUpdates() {
- if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
- mAttachInfo.mHardwareRenderer.validate()) {
+ if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
mAttachInfo.mHardwareRenderer.flushLayerUpdates();
}
}
@@ -926,17 +931,12 @@
return mAppVisible ? mView.getVisibility() : View.GONE;
}
-// void disposeResizeBuffer() {
-// if (mResizeBuffer != null && mAttachInfo.mHardwareRenderer != null) {
-// mAttachInfo.mHardwareRenderer.safelyRun(new Runnable() {
-// @Override
-// public void run() {
-// mResizeBuffer.destroy();
-// mResizeBuffer = null;
-// }
-// });
-// }
-// }
+ void disposeResizeBuffer() {
+ if (mResizeBuffer != null) {
+ mResizeBuffer.destroy();
+ mResizeBuffer = null;
+ }
+ }
/**
* Add LayoutTransition to the list of transitions to be started in the next traversal.
@@ -1447,76 +1447,63 @@
final boolean visibleInsetsChanged = !mPendingVisibleInsets.equals(
mAttachInfo.mVisibleInsets);
if (contentInsetsChanged) {
-// TODO: Do something with this...
-// if (mWidth > 0 && mHeight > 0 && lp != null &&
-// ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
-// & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
-// mSurface != null && mSurface.isValid() &&
-// !mAttachInfo.mTurnOffWindowResizeAnim &&
-// mAttachInfo.mHardwareRenderer != null &&
-// mAttachInfo.mHardwareRenderer.isEnabled() &&
-// mAttachInfo.mHardwareRenderer.validate() &&
-// lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
-//
-// disposeResizeBuffer();
-//
-// boolean completed = false;
-// HardwareCanvas hwRendererCanvas = mAttachInfo.mHardwareRenderer.getCanvas();
-// HardwareCanvas layerCanvas = null;
-// try {
-// if (mResizeBuffer == null) {
-// mResizeBuffer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
-// mWidth, mHeight, false);
-// } else if (mResizeBuffer.getWidth() != mWidth ||
-// mResizeBuffer.getHeight() != mHeight) {
-// mResizeBuffer.resize(mWidth, mHeight);
-// }
-// // TODO: should handle create/resize failure
-// layerCanvas = mResizeBuffer.start(hwRendererCanvas);
-// final int restoreCount = layerCanvas.save();
-//
-// int yoff;
-// final boolean scrolling = mScroller != null
-// && mScroller.computeScrollOffset();
-// if (scrolling) {
-// yoff = mScroller.getCurrY();
-// mScroller.abortAnimation();
-// } else {
-// yoff = mScrollY;
-// }
-//
-// layerCanvas.translate(0, -yoff);
-// if (mTranslator != null) {
-// mTranslator.translateCanvas(layerCanvas);
-// }
-//
-// DisplayList displayList = mView.mDisplayList;
-// if (displayList != null && displayList.isValid()) {
-// layerCanvas.drawDisplayList(displayList, null,
-// DisplayList.FLAG_CLIP_CHILDREN);
-// } else {
-// mView.draw(layerCanvas);
-// }
-//
-// drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
-//
-// mResizeBufferStartTime = SystemClock.uptimeMillis();
-// mResizeBufferDuration = mView.getResources().getInteger(
-// com.android.internal.R.integer.config_mediumAnimTime);
-// completed = true;
-//
-// layerCanvas.restoreToCount(restoreCount);
-// } catch (OutOfMemoryError e) {
-// Log.w(TAG, "Not enough memory for content change anim buffer", e);
-// } finally {
-// if (mResizeBuffer != null) {
-// mResizeBuffer.end(hwRendererCanvas);
-// if (!completed) {
-// disposeResizeBuffer();
-// }
-// }
-// }
-// }
+ if (mWidth > 0 && mHeight > 0 && lp != null &&
+ ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility)
+ & View.SYSTEM_UI_LAYOUT_FLAGS) == 0 &&
+ mSurface != null && mSurface.isValid() &&
+ !mAttachInfo.mTurnOffWindowResizeAnim &&
+ mAttachInfo.mHardwareRenderer != null &&
+ mAttachInfo.mHardwareRenderer.isEnabled() &&
+ lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
+
+ disposeResizeBuffer();
+
+ if (mResizeBuffer == null) {
+ mResizeBuffer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+ mWidth, mHeight);
+ }
+ mResizeBuffer.prepare(mWidth, mHeight, false);
+ DisplayList layerDisplayList = mResizeBuffer.startRecording();
+ HardwareCanvas layerCanvas = layerDisplayList.start(mWidth, mHeight);
+ final int restoreCount = layerCanvas.save();
+
+ int yoff;
+ final boolean scrolling = mScroller != null
+ && mScroller.computeScrollOffset();
+ if (scrolling) {
+ yoff = mScroller.getCurrY();
+ mScroller.abortAnimation();
+ } else {
+ yoff = mScrollY;
+ }
+
+ layerCanvas.translate(0, -yoff);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(layerCanvas);
+ }
+
+ DisplayList displayList = mView.mDisplayList;
+ if (displayList != null && displayList.isValid()) {
+ layerCanvas.drawDisplayList(displayList, null,
+ DisplayList.FLAG_CLIP_CHILDREN);
+ } else {
+ mView.draw(layerCanvas);
+ }
+
+ drawAccessibilityFocusedDrawableIfNeeded(layerCanvas);
+
+ mResizeBufferStartTime = SystemClock.uptimeMillis();
+ mResizeBufferDuration = mView.getResources().getInteger(
+ com.android.internal.R.integer.config_mediumAnimTime);
+
+ layerCanvas.restoreToCount(restoreCount);
+ layerDisplayList.end();
+ layerDisplayList.setCaching(true);
+ layerDisplayList.setLeftTopRightBottom(0, 0, mWidth, mHeight);
+ mTempRect.set(0, 0, mWidth, mHeight);
+ mResizeBuffer.endRecording(mTempRect);
+ mAttachInfo.mHardwareRenderer.flushLayerUpdates();
+ }
mAttachInfo.mContentInsets.set(mPendingContentInsets);
if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: "
+ mAttachInfo.mContentInsets);
@@ -1576,7 +1563,7 @@
if (mScroller != null) {
mScroller.abortAnimation();
}
-// disposeResizeBuffer();
+ disposeResizeBuffer();
// Our surface is gone
if (mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled()) {
@@ -2175,10 +2162,10 @@
@Override
public void onHardwarePostDraw(HardwareCanvas canvas) {
-// if (mResizeBuffer != null) {
-// mResizePaint.setAlpha(mResizeAlpha);
-// canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
-// }
+ if (mResizeBuffer != null) {
+ mResizePaint.setAlpha(mResizeAlpha);
+ canvas.drawHardwareLayer(mResizeBuffer, 0.0f, mHardwareYOffset, mResizePaint);
+ }
// TODO: this
if (!HardwareRenderer.sUseRenderThread) {
drawAccessibilityFocusedDrawableIfNeeded(canvas);
@@ -2337,17 +2324,17 @@
final boolean scalingRequired = attachInfo.mScalingRequired;
int resizeAlpha = 0;
-// if (mResizeBuffer != null) {
-// long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
-// if (deltaTime < mResizeBufferDuration) {
-// float amt = deltaTime/(float) mResizeBufferDuration;
-// amt = mResizeInterpolator.getInterpolation(amt);
-// animating = true;
-// resizeAlpha = 255 - (int)(amt*255);
-// } else {
-// disposeResizeBuffer();
-// }
-// }
+ if (mResizeBuffer != null) {
+ long deltaTime = SystemClock.uptimeMillis() - mResizeBufferStartTime;
+ if (deltaTime < mResizeBufferDuration) {
+ float amt = deltaTime/(float) mResizeBufferDuration;
+ amt = mResizeInterpolator.getInterpolation(amt);
+ animating = true;
+ resizeAlpha = 255 - (int)(amt*255);
+ } else {
+ disposeResizeBuffer();
+ }
+ }
final Rect dirty = mDirty;
if (mSurfaceHolder != null) {
@@ -2357,7 +2344,7 @@
if (mScroller != null) {
mScroller.abortAnimation();
}
-// disposeResizeBuffer();
+ disposeResizeBuffer();
}
return;
}
@@ -2720,7 +2707,7 @@
if (scrollY != mScrollY) {
if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
+ mScrollY + " , new=" + scrollY);
- if (!immediate /*&& mResizeBuffer == null*/) {
+ if (!immediate && mResizeBuffer == null) {
if (mScroller == null) {
mScroller = new Scroller(mView.getContext());
}
@@ -2849,10 +2836,6 @@
void dispatchDetachedFromWindow() {
if (mView != null && mView.mAttachInfo != null) {
- if (mAttachInfo.mHardwareRenderer != null &&
- mAttachInfo.mHardwareRenderer.isEnabled()) {
- mAttachInfo.mHardwareRenderer.validate();
- }
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
mView.dispatchDetachedFromWindow();
}
@@ -2930,9 +2913,6 @@
mView.dispatchConfigurationChanged(config);
}
}
-
- mFlipControllerFallbackKeys =
- mContext.getResources().getBoolean(R.bool.flip_controller_fallback_keys);
}
/**
@@ -4001,7 +3981,6 @@
private final SyntheticJoystickHandler mJoystick = new SyntheticJoystickHandler();
private final SyntheticTouchNavigationHandler mTouchNavigation =
new SyntheticTouchNavigationHandler();
- private final SyntheticKeyHandler mKeys = new SyntheticKeyHandler();
public SyntheticInputStage() {
super(null);
@@ -4024,12 +4003,7 @@
mTouchNavigation.process(event);
return FINISH_HANDLED;
}
- } else if (q.mEvent instanceof KeyEvent) {
- if (mKeys.process((KeyEvent) q.mEvent)) {
- return FINISH_HANDLED;
- }
}
-
return FORWARD;
}
@@ -4854,71 +4828,6 @@
};
}
- private KeyEvent getSyntheticFallbackKey(KeyEvent event) {
- // In some locales (like Japan) controllers use B for confirm and A for back, rather
- // than vice versa, so we need to special case this here since the input system itself
- // is not locale-aware.
- int keyCode;
- switch(event.getKeyCode()) {
- case KeyEvent.KEYCODE_BUTTON_A:
- case KeyEvent.KEYCODE_BUTTON_C:
- case KeyEvent.KEYCODE_BUTTON_X:
- case KeyEvent.KEYCODE_BUTTON_Z:
- keyCode = mFlipControllerFallbackKeys ?
- KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_DPAD_CENTER;
- break;
- case KeyEvent.KEYCODE_BUTTON_B:
- case KeyEvent.KEYCODE_BUTTON_Y:
- keyCode = mFlipControllerFallbackKeys ?
- KeyEvent.KEYCODE_DPAD_CENTER : KeyEvent.KEYCODE_BACK;
- break;
- case KeyEvent.KEYCODE_BUTTON_THUMBL:
- case KeyEvent.KEYCODE_BUTTON_THUMBR:
- case KeyEvent.KEYCODE_BUTTON_START:
- case KeyEvent.KEYCODE_BUTTON_1:
- case KeyEvent.KEYCODE_BUTTON_2:
- case KeyEvent.KEYCODE_BUTTON_3:
- case KeyEvent.KEYCODE_BUTTON_4:
- case KeyEvent.KEYCODE_BUTTON_5:
- case KeyEvent.KEYCODE_BUTTON_6:
- case KeyEvent.KEYCODE_BUTTON_7:
- case KeyEvent.KEYCODE_BUTTON_8:
- case KeyEvent.KEYCODE_BUTTON_9:
- case KeyEvent.KEYCODE_BUTTON_10:
- case KeyEvent.KEYCODE_BUTTON_11:
- case KeyEvent.KEYCODE_BUTTON_12:
- case KeyEvent.KEYCODE_BUTTON_13:
- case KeyEvent.KEYCODE_BUTTON_14:
- case KeyEvent.KEYCODE_BUTTON_15:
- case KeyEvent.KEYCODE_BUTTON_16:
- keyCode = KeyEvent.KEYCODE_DPAD_CENTER;
- break;
- case KeyEvent.KEYCODE_BUTTON_SELECT:
- case KeyEvent.KEYCODE_BUTTON_MODE:
- keyCode = KeyEvent.KEYCODE_MENU;
- default:
- return null;
- }
- return KeyEvent.obtain(event.getDownTime(), event.getEventTime(),
- event.getAction(), keyCode, event.getRepeatCount(), event.getMetaState(),
- event.getDeviceId(), event.getScanCode(),
- event.getFlags() | KeyEvent.FLAG_FALLBACK, event.getSource(), null);
- }
-
-
- final class SyntheticKeyHandler {
-
- public boolean process(KeyEvent event) {
- KeyEvent syntheticKey = getSyntheticFallbackKey(event);
- if (syntheticKey != null) {
- enqueueInputEvent(syntheticKey);
- return true;
- }
- return false;
- }
-
- }
-
/**
* Returns true if the key is used for keyboard navigation.
* @param keyEvent The key event.
@@ -5610,24 +5519,23 @@
}
private void deliverInputEvent(QueuedInputEvent q) {
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
- try {
- if (mInputEventConsistencyVerifier != null) {
- mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
- }
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
+ q.mEvent.getSequenceNumber());
+ if (mInputEventConsistencyVerifier != null) {
+ mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
+ }
- InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
- if (stage != null) {
- stage.deliver(q);
- } else {
- finishInputEvent(q);
- }
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
+ if (stage != null) {
+ stage.deliver(q);
+ } else {
+ finishInputEvent(q);
}
}
private void finishInputEvent(QueuedInputEvent q) {
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "deliverInputEvent",
+ q.mEvent.getSequenceNumber());
if (q.mReceiver != null) {
boolean handled = (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
q.mReceiver.finishInputEvent(q.mEvent, handled);
@@ -5857,29 +5765,22 @@
// Some fallback keys are decided by the ViewRoot as they might have special
// properties (e.g. are locale aware). These take precedence over fallbacks defined by
// the kcm.
- KeyEvent fallbackEvent = getSyntheticFallbackKey(event);
+ final KeyCharacterMap kcm = event.getKeyCharacterMap();
+ final int keyCode = event.getKeyCode();
+ final int metaState = event.getMetaState();
- if (fallbackEvent == null) {
- final KeyCharacterMap kcm = event.getKeyCharacterMap();
- final int keyCode = event.getKeyCode();
- final int metaState = event.getMetaState();
-
- // Check for fallback actions specified by the key character map.
- KeyCharacterMap.FallbackAction fallbackAction =
- kcm.getFallbackAction(keyCode, metaState);
- if (fallbackAction != null) {
- final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
- fallbackEvent = KeyEvent.obtain(
- event.getDownTime(), event.getEventTime(),
- event.getAction(), fallbackAction.keyCode,
- event.getRepeatCount(), fallbackAction.metaState,
- event.getDeviceId(), event.getScanCode(),
- flags, event.getSource(), null);
- fallbackAction.recycle();
-
- }
- }
- if (fallbackEvent != null) {
+ // Check for fallback actions specified by the key character map.
+ KeyCharacterMap.FallbackAction fallbackAction =
+ kcm.getFallbackAction(keyCode, metaState);
+ if (fallbackAction != null) {
+ final int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK;
+ KeyEvent fallbackEvent = KeyEvent.obtain(
+ event.getDownTime(), event.getEventTime(),
+ event.getAction(), fallbackAction.keyCode,
+ event.getRepeatCount(), fallbackAction.metaState,
+ event.getDeviceId(), event.getScanCode(),
+ flags, event.getSource(), null);
+ fallbackAction.recycle();
dispatchInputEvent(fallbackEvent);
}
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index d9e140e..75656545 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -119,20 +119,6 @@
public final static int ACTION_PASS_TO_USER = 0x00000001;
/**
- * This key event should wake the device.
- * To be returned from {@link #interceptKeyBeforeQueueing}.
- * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}.
- */
- public final static int ACTION_WAKE_UP = 0x00000002;
-
- /**
- * This key event should put the device to sleep (and engage keyguard if necessary)
- * To be returned from {@link #interceptKeyBeforeQueueing}.
- * Do not return this and {@link #ACTION_WAKE_UP} or {@link #ACTION_PASS_TO_USER}.
- */
- public final static int ACTION_GO_TO_SLEEP = 0x00000004;
-
- /**
* Interface to the Window Manager state associated with a particular
* window. You can hold on to an instance of this interface from the call
* to prepareAddWindow() until removeWindow().
@@ -760,8 +746,7 @@
* @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on
*
- * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
- * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+ * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
@@ -774,10 +759,9 @@
* because it's the most fragile.
* @param policyFlags The policy flags associated with the motion.
*
- * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
- * {@link #ACTION_WAKE_UP} and {@link #ACTION_GO_TO_SLEEP} flags.
+ * @return Actions flags: may be {@link #ACTION_PASS_TO_USER}.
*/
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 61aabea..560d0c9 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -282,6 +282,22 @@
*/
public static final int ACTION_DISMISS = 0x00100000;
+ /**
+ * Action that sets the text of the node. Performing the action without argument, using <code>
+ * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
+ * cursor at the end of text.
+ * <p>
+ * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
+ * <strong>Example:</strong>
+ * <code><pre><p>
+ * Bundle arguments = new Bundle();
+ * arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,
+ * "android");
+ * info.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
+ * </code></pre></p>
+ */
+ public static final int ACTION_SET_TEXT = 0x00200000;
+
// Action arguments
/**
@@ -351,6 +367,18 @@
public static final String ACTION_ARGUMENT_SELECTION_END_INT =
"ACTION_ARGUMENT_SELECTION_END_INT";
+ /**
+ * Argument for specifying the text content to set
+ * <p>
+ * <strong>Type:</strong> CharSequence<br>
+ * <strong>Actions:</strong> {@link #ACTION_SET_TEXT}
+ * </p>
+ *
+ * @see #ACTION_SET_TEXT
+ */
+ public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
+ "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
+
// Focus types
/**
@@ -2283,6 +2311,7 @@
parcel.writeInt(mCollectionInfo.getRowCount());
parcel.writeInt(mCollectionInfo.getColumnCount());
parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0);
+ parcel.writeInt(mCollectionInfo.getSelectionMode());
} else {
parcel.writeInt(0);
}
@@ -2294,6 +2323,7 @@
parcel.writeInt(mCollectionItemInfo.getRowIndex());
parcel.writeInt(mCollectionItemInfo.getRowSpan());
parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0);
+ parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
} else {
parcel.writeInt(0);
}
@@ -2420,7 +2450,8 @@
mCollectionInfo = CollectionInfo.obtain(
parcel.readInt(),
parcel.readInt(),
- parcel.readInt() == 1);
+ parcel.readInt() == 1,
+ parcel.readInt());
}
if (parcel.readInt() == 1) {
@@ -2429,6 +2460,7 @@
parcel.readInt(),
parcel.readInt(),
parcel.readInt(),
+ parcel.readInt() == 1,
parcel.readInt() == 1);
}
}
@@ -2786,6 +2818,15 @@
* </p>
*/
public static final class CollectionInfo {
+ /** Selection mode where items are not selectable. */
+ public static final int SELECTION_MODE_NONE = 0;
+
+ /** Selection mode where a single item may be selected. */
+ public static final int SELECTION_MODE_SINGLE = 1;
+
+ /** Selection mode where multiple items may be selected. */
+ public static final int SELECTION_MODE_MULTIPLE = 2;
+
private static final int MAX_POOL_SIZE = 20;
private static final SynchronizedPool<CollectionInfo> sPool =
@@ -2794,17 +2835,17 @@
private int mRowCount;
private int mColumnCount;
private boolean mHierarchical;
+ private int mSelectionMode;
/**
* Obtains a pooled instance that is a clone of another one.
*
* @param other The instance to clone.
- *
* @hide
*/
public static CollectionInfo obtain(CollectionInfo other) {
- return CollectionInfo.obtain(other.mRowCount, other.mColumnCount,
- other.mHierarchical);
+ return CollectionInfo.obtain(other.mRowCount, other.mColumnCount, other.mHierarchical,
+ other.mSelectionMode);
}
/**
@@ -2816,9 +2857,34 @@
*/
public static CollectionInfo obtain(int rowCount, int columnCount,
boolean hierarchical) {
- CollectionInfo info = sPool.acquire();
- return (info != null) ? info : new CollectionInfo(rowCount,
- columnCount, hierarchical);
+ return obtain(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
+ }
+
+ /**
+ * Obtains a pooled instance.
+ *
+ * @param rowCount The number of rows.
+ * @param columnCount The number of columns.
+ * @param hierarchical Whether the collection is hierarchical.
+ * @param selectionMode The collection's selection mode, one of:
+ * <ul>
+ * <li>{@link #SELECTION_MODE_NONE}
+ * <li>{@link #SELECTION_MODE_SINGLE}
+ * <li>{@link #SELECTION_MODE_MULTIPLE}
+ * </ul>
+ */
+ public static CollectionInfo obtain(int rowCount, int columnCount,
+ boolean hierarchical, int selectionMode) {
+ final CollectionInfo info = sPool.acquire();
+ if (info == null) {
+ return new CollectionInfo(rowCount, columnCount, hierarchical, selectionMode);
+ }
+
+ info.mRowCount = rowCount;
+ info.mColumnCount = columnCount;
+ info.mHierarchical = hierarchical;
+ info.mSelectionMode = selectionMode;
+ return info;
}
/**
@@ -2827,12 +2893,14 @@
* @param rowCount The number of rows.
* @param columnCount The number of columns.
* @param hierarchical Whether the collection is hierarchical.
+ * @param selectionMode The collection's selection mode.
*/
- private CollectionInfo(int rowCount, int columnCount,
- boolean hierarchical) {
+ private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
+ int selectionMode) {
mRowCount = rowCount;
mColumnCount = columnCount;
mHierarchical = hierarchical;
+ mSelectionMode = selectionMode;
}
/**
@@ -2863,6 +2931,20 @@
}
/**
+ * Gets the collection's selection mode.
+ *
+ * @return The collection's selection mode, one of:
+ * <ul>
+ * <li>{@link #SELECTION_MODE_NONE}
+ * <li>{@link #SELECTION_MODE_SINGLE}
+ * <li>{@link #SELECTION_MODE_MULTIPLE}
+ * </ul>
+ */
+ public int getSelectionMode() {
+ return mSelectionMode;
+ }
+
+ /**
* Recycles this instance.
*/
void recycle() {
@@ -2874,6 +2956,7 @@
mRowCount = 0;
mColumnCount = 0;
mHierarchical = false;
+ mSelectionMode = SELECTION_MODE_NONE;
}
}
@@ -2899,12 +2982,11 @@
* Obtains a pooled instance that is a clone of another one.
*
* @param other The instance to clone.
- *
* @hide
*/
public static CollectionItemInfo obtain(CollectionItemInfo other) {
- return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan,
- other.mColumnIndex, other.mColumnSpan, other.mHeading);
+ return CollectionItemInfo.obtain(other.mRowIndex, other.mRowSpan, other.mColumnIndex,
+ other.mColumnSpan, other.mHeading, other.mSelected);
}
/**
@@ -2918,9 +3000,34 @@
*/
public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
int columnIndex, int columnSpan, boolean heading) {
- CollectionItemInfo info = sPool.acquire();
- return (info != null) ? info : new CollectionItemInfo(rowIndex,
- rowSpan, columnIndex, columnSpan, heading);
+ return obtain(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
+ }
+
+ /**
+ * Obtains a pooled instance.
+ *
+ * @param rowIndex The row index at which the item is located.
+ * @param rowSpan The number of rows the item spans.
+ * @param columnIndex The column index at which the item is located.
+ * @param columnSpan The number of columns the item spans.
+ * @param heading Whether the item is a heading.
+ * @param selected Whether the item is selected.
+ */
+ public static CollectionItemInfo obtain(int rowIndex, int rowSpan,
+ int columnIndex, int columnSpan, boolean heading, boolean selected) {
+ final CollectionItemInfo info = sPool.acquire();
+ if (info == null) {
+ return new CollectionItemInfo(
+ rowIndex, rowSpan, columnIndex, columnSpan, heading, selected);
+ }
+
+ info.mRowIndex = rowIndex;
+ info.mRowSpan = rowSpan;
+ info.mColumnIndex = columnIndex;
+ info.mColumnSpan = columnSpan;
+ info.mHeading = heading;
+ info.mSelected = selected;
+ return info;
}
private boolean mHeading;
@@ -2928,6 +3035,7 @@
private int mRowIndex;
private int mColumnSpan;
private int mRowSpan;
+ private boolean mSelected;
/**
* Creates a new instance.
@@ -2938,13 +3046,14 @@
* @param columnSpan The number of columns the item spans.
* @param heading Whether the item is a heading.
*/
- private CollectionItemInfo(int rowIndex, int rowSpan,
- int columnIndex, int columnSpan, boolean heading) {
+ private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
+ boolean heading, boolean selected) {
mRowIndex = rowIndex;
mRowSpan = rowSpan;
mColumnIndex = columnIndex;
mColumnSpan = columnSpan;
mHeading = heading;
+ mSelected = selected;
}
/**
@@ -2994,6 +3103,15 @@
}
/**
+ * Gets if the collection item is selected.
+ *
+ * @return If the item is selected.
+ */
+ public boolean isSelected() {
+ return mSelected;
+ }
+
+ /**
* Recycles this instance.
*/
void recycle() {
@@ -3007,6 +3125,7 @@
mRowIndex = 0;
mRowSpan = 0;
mHeading = false;
+ mSelected = false;
}
}
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index 97db84b..b4944be 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -312,18 +312,25 @@
}
}
+ int disconnectedNodeCount = 0;
// Check for disconnected nodes or ones from another window.
for (int i = 0; i < mCacheImpl.size(); i++) {
AccessibilityNodeInfo info = mCacheImpl.valueAt(i);
if (!seen.contains(info)) {
if (info.getWindowId() == windowId) {
- Log.e(LOG_TAG, "Disconneced node: " + info);
+ if (DEBUG) {
+ Log.e(LOG_TAG, "Disconnected node: " + info);
+ }
+ disconnectedNodeCount++;
} else {
Log.e(LOG_TAG, "Node from: " + info.getWindowId() + " not from:"
+ windowId + " " + info);
}
}
}
+ if (disconnectedNodeCount > 0) {
+ Log.e(LOG_TAG, String.format("Found %d disconnected nodes", disconnectedNodeCount));
+ }
}
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 5df5811..9f2bf33 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2007-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
@@ -64,7 +64,7 @@
* The Service that implements this input method component.
*/
final ResolveInfo mService;
-
+
/**
* The unique string Id to identify the input method. This is generated
* from the input method component.
@@ -144,22 +144,22 @@
throw new XmlPullParserException("No "
+ InputMethod.SERVICE_META_DATA + " meta-data");
}
-
+
Resources res = pm.getResourcesForApplication(si.applicationInfo);
-
+
AttributeSet attrs = Xml.asAttributeSet(parser);
-
+
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
}
-
+
String nodeName = parser.getName();
if (!"input-method".equals(nodeName)) {
throw new XmlPullParserException(
"Meta-data does not start with input-method tag");
}
-
+
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.InputMethod);
settingsActivityComponent = sa.getString(
@@ -338,7 +338,7 @@
/**
* Load the user-displayed label for this input method.
- *
+ *
* @param pm Supply a PackageManager used to load the input method's
* resources.
*/
@@ -348,7 +348,7 @@
/**
* Load the user-displayed icon for this input method.
- *
+ *
* @param pm Supply a PackageManager used to load the input method's
* resources.
*/
@@ -362,7 +362,7 @@
* an {@link android.content.Intent} whose action is MAIN and with an
* explicit {@link android.content.ComponentName}
* composed of {@link #getPackageName} and the class name returned here.
- *
+ *
* <p>A null will be returned if there is no settings activity associated
* with the input method.
*/
@@ -419,7 +419,7 @@
pw.println(prefix + "Service:");
mService.dump(pw, prefix + " ");
}
-
+
@Override
public String toString() {
return "InputMethodInfo{" + mId
@@ -430,7 +430,7 @@
/**
* Used to test whether the given parameter object is an
* {@link InputMethodInfo} and its Id is the same to this one.
- *
+ *
* @return true if the given parameter object is an
* {@link InputMethodInfo} and its Id is the same to this one.
*/
@@ -467,7 +467,7 @@
/**
* Used to package this object into a {@link Parcel}.
- *
+ *
* @param dest The {@link Parcel} to be written.
* @param flags The flags used for parceling.
*/
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 13febe9..86fdae3 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,6 +36,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.util.LongSparseArray;
+import android.util.MathUtils;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.StateSet;
@@ -60,6 +61,9 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.BaseInputConnection;
@@ -418,7 +422,7 @@
/**
* Handles scrolling between positions within the list.
*/
- PositionScroller mPositionScroller;
+ AbsPositionScroller mPositionScroller;
/**
* The offset in pixels form the top of the AdapterView to the top
@@ -700,6 +704,11 @@
private SavedState mPendingSync;
/**
+ * Whether the view is in the process of detaching from its window.
+ */
+ private boolean mIsDetaching;
+
+ /**
* Interface definition for a callback to be invoked when the list or grid
* has been scrolled.
*/
@@ -1488,6 +1497,21 @@
}
}
+ int getSelectionModeForAccessibility() {
+ final int choiceMode = getChoiceMode();
+ switch (choiceMode) {
+ case CHOICE_MODE_NONE:
+ return CollectionInfo.SELECTION_MODE_NONE;
+ case CHOICE_MODE_SINGLE:
+ return CollectionInfo.SELECTION_MODE_SINGLE;
+ case CHOICE_MODE_MULTIPLE:
+ case CHOICE_MODE_MULTIPLE_MODAL:
+ return CollectionInfo.SELECTION_MODE_MULTIPLE;
+ default:
+ return CollectionInfo.SELECTION_MODE_NONE;
+ }
+ }
+
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (super.performAccessibilityAction(action, arguments)) {
@@ -2150,20 +2174,11 @@
}
/**
- * @return the direct child that contains accessibility focus, or null if no
+ * @param focusedView view that holds accessibility focus
+ * @return direct child that contains accessibility focus, or null if no
* child contains accessibility focus
*/
- View getAccessibilityFocusedChild() {
- final ViewRootImpl viewRootImpl = getViewRootImpl();
- if (viewRootImpl == null) {
- return null;
- }
-
- View focusedView = viewRootImpl.getAccessibilityFocusedHost();
- if (focusedView == null) {
- return null;
- }
-
+ View getAccessibilityFocusedChild(View focusedView) {
ViewParent viewParent = focusedView.getParent();
while ((viewParent instanceof View) && (viewParent != this)) {
focusedView = (View) viewParent;
@@ -2290,10 +2305,16 @@
// data and discard the view if we fail.
final View transientView = mRecycler.getTransientStateView(position);
if (transientView != null) {
- final View updatedView = mAdapter.getView(position, transientView, this);
- if (updatedView != transientView) {
- // Failed to re-bind the data, scrap the obtained view.
- mRecycler.addScrapView(updatedView, position);
+ final LayoutParams params = (LayoutParams) transientView.getLayoutParams();
+
+ // If the view type hasn't changed, attempt to re-bind the data.
+ if (params.viewType == mAdapter.getItemViewType(position)) {
+ final View updatedView = mAdapter.getView(position, transientView, this);
+
+ // If we failed to re-bind the data, scrap the obtained view.
+ if (updatedView != transientView) {
+ mRecycler.addScrapView(updatedView, position);
+ }
}
// Scrap view implies temporary detachment.
@@ -2310,12 +2331,6 @@
} else {
isScrap[0] = true;
- // Clear any system-managed transient state so that we can
- // recycle this view and bind it to different data.
- if (child.isAccessibilityFocused()) {
- child.clearAccessibilityFocus();
- }
-
child.dispatchFinishTemporaryDetach();
}
}
@@ -2778,6 +2793,8 @@
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ mIsDetaching = true;
+
// Dismiss the popup in case onSaveInstanceState() was not invoked
dismissPopup();
@@ -2826,6 +2843,8 @@
removeCallbacks(mTouchModeReset);
mTouchModeReset.run();
}
+
+ mIsDetaching = false;
}
@Override
@@ -3452,7 +3471,7 @@
mPositionScroller.stop();
}
- if (!isAttachedToWindow()) {
+ if (mIsDetaching || !isAttachedToWindow()) {
// Something isn't right.
// Since we rely on being attached to get data set change notifications,
// don't risk doing anything where we might try to resync and find things
@@ -3691,7 +3710,7 @@
mTouchMode = TOUCH_MODE_REST;
child.setPressed(false);
setPressed(false);
- if (!mDataChanged && isAttachedToWindow()) {
+ if (!mDataChanged && !mIsDetaching && isAttachedToWindow()) {
performClick.run();
}
}
@@ -3966,7 +3985,7 @@
mPositionScroller.stop();
}
- if (!isAttachedToWindow()) {
+ if (mIsDetaching || !isAttachedToWindow()) {
// Something isn't right.
// Since we rely on being attached to get data set change notifications,
// don't risk doing anything where we might try to resync and find things
@@ -4371,447 +4390,6 @@
}
}
- class PositionScroller implements Runnable {
- private static final int SCROLL_DURATION = 200;
-
- private static final int MOVE_DOWN_POS = 1;
- private static final int MOVE_UP_POS = 2;
- private static final int MOVE_DOWN_BOUND = 3;
- private static final int MOVE_UP_BOUND = 4;
- private static final int MOVE_OFFSET = 5;
-
- private int mMode;
- private int mTargetPos;
- private int mBoundPos;
- private int mLastSeenPos;
- private int mScrollDuration;
- private final int mExtraScroll;
-
- private int mOffsetFromTop;
-
- PositionScroller() {
- mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
- }
-
- void start(final int position) {
- stop();
-
- if (mDataChanged) {
- // Wait until we're back in a stable state to try this.
- mPositionScrollAfterLayout = new Runnable() {
- @Override public void run() {
- start(position);
- }
- };
- return;
- }
-
- final int childCount = getChildCount();
- if (childCount == 0) {
- // Can't scroll without children.
- return;
- }
-
- final int firstPos = mFirstPosition;
- final int lastPos = firstPos + childCount - 1;
-
- int viewTravelCount;
- int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
- if (clampedPosition < firstPos) {
- viewTravelCount = firstPos - clampedPosition + 1;
- mMode = MOVE_UP_POS;
- } else if (clampedPosition > lastPos) {
- viewTravelCount = clampedPosition - lastPos + 1;
- mMode = MOVE_DOWN_POS;
- } else {
- scrollToVisible(clampedPosition, INVALID_POSITION, SCROLL_DURATION);
- return;
- }
-
- if (viewTravelCount > 0) {
- mScrollDuration = SCROLL_DURATION / viewTravelCount;
- } else {
- mScrollDuration = SCROLL_DURATION;
- }
- mTargetPos = clampedPosition;
- mBoundPos = INVALID_POSITION;
- mLastSeenPos = INVALID_POSITION;
-
- postOnAnimation(this);
- }
-
- void start(final int position, final int boundPosition) {
- stop();
-
- if (boundPosition == INVALID_POSITION) {
- start(position);
- return;
- }
-
- if (mDataChanged) {
- // Wait until we're back in a stable state to try this.
- mPositionScrollAfterLayout = new Runnable() {
- @Override public void run() {
- start(position, boundPosition);
- }
- };
- return;
- }
-
- final int childCount = getChildCount();
- if (childCount == 0) {
- // Can't scroll without children.
- return;
- }
-
- final int firstPos = mFirstPosition;
- final int lastPos = firstPos + childCount - 1;
-
- int viewTravelCount;
- int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
- if (clampedPosition < firstPos) {
- final int boundPosFromLast = lastPos - boundPosition;
- if (boundPosFromLast < 1) {
- // Moving would shift our bound position off the screen. Abort.
- return;
- }
-
- final int posTravel = firstPos - clampedPosition + 1;
- final int boundTravel = boundPosFromLast - 1;
- if (boundTravel < posTravel) {
- viewTravelCount = boundTravel;
- mMode = MOVE_UP_BOUND;
- } else {
- viewTravelCount = posTravel;
- mMode = MOVE_UP_POS;
- }
- } else if (clampedPosition > lastPos) {
- final int boundPosFromFirst = boundPosition - firstPos;
- if (boundPosFromFirst < 1) {
- // Moving would shift our bound position off the screen. Abort.
- return;
- }
-
- final int posTravel = clampedPosition - lastPos + 1;
- final int boundTravel = boundPosFromFirst - 1;
- if (boundTravel < posTravel) {
- viewTravelCount = boundTravel;
- mMode = MOVE_DOWN_BOUND;
- } else {
- viewTravelCount = posTravel;
- mMode = MOVE_DOWN_POS;
- }
- } else {
- scrollToVisible(clampedPosition, boundPosition, SCROLL_DURATION);
- return;
- }
-
- if (viewTravelCount > 0) {
- mScrollDuration = SCROLL_DURATION / viewTravelCount;
- } else {
- mScrollDuration = SCROLL_DURATION;
- }
- mTargetPos = clampedPosition;
- mBoundPos = boundPosition;
- mLastSeenPos = INVALID_POSITION;
-
- postOnAnimation(this);
- }
-
- void startWithOffset(int position, int offset) {
- startWithOffset(position, offset, SCROLL_DURATION);
- }
-
- void startWithOffset(final int position, int offset, final int duration) {
- stop();
-
- if (mDataChanged) {
- // Wait until we're back in a stable state to try this.
- final int postOffset = offset;
- mPositionScrollAfterLayout = new Runnable() {
- @Override public void run() {
- startWithOffset(position, postOffset, duration);
- }
- };
- return;
- }
-
- final int childCount = getChildCount();
- if (childCount == 0) {
- // Can't scroll without children.
- return;
- }
-
- offset += getPaddingTop();
-
- mTargetPos = Math.max(0, Math.min(getCount() - 1, position));
- mOffsetFromTop = offset;
- mBoundPos = INVALID_POSITION;
- mLastSeenPos = INVALID_POSITION;
- mMode = MOVE_OFFSET;
-
- final int firstPos = mFirstPosition;
- final int lastPos = firstPos + childCount - 1;
-
- int viewTravelCount;
- if (mTargetPos < firstPos) {
- viewTravelCount = firstPos - mTargetPos;
- } else if (mTargetPos > lastPos) {
- viewTravelCount = mTargetPos - lastPos;
- } else {
- // On-screen, just scroll.
- final int targetTop = getChildAt(mTargetPos - firstPos).getTop();
- smoothScrollBy(targetTop - offset, duration, true);
- return;
- }
-
- // Estimate how many screens we should travel
- final float screenTravelCount = (float) viewTravelCount / childCount;
- mScrollDuration = screenTravelCount < 1 ?
- duration : (int) (duration / screenTravelCount);
- mLastSeenPos = INVALID_POSITION;
-
- postOnAnimation(this);
- }
-
- /**
- * Scroll such that targetPos is in the visible padded region without scrolling
- * boundPos out of view. Assumes targetPos is onscreen.
- */
- void scrollToVisible(int targetPos, int boundPos, int duration) {
- final int firstPos = mFirstPosition;
- final int childCount = getChildCount();
- final int lastPos = firstPos + childCount - 1;
- final int paddedTop = mListPadding.top;
- final int paddedBottom = getHeight() - mListPadding.bottom;
-
- if (targetPos < firstPos || targetPos > lastPos) {
- Log.w(TAG, "scrollToVisible called with targetPos " + targetPos +
- " not visible [" + firstPos + ", " + lastPos + "]");
- }
- if (boundPos < firstPos || boundPos > lastPos) {
- // boundPos doesn't matter, it's already offscreen.
- boundPos = INVALID_POSITION;
- }
-
- final View targetChild = getChildAt(targetPos - firstPos);
- final int targetTop = targetChild.getTop();
- final int targetBottom = targetChild.getBottom();
- int scrollBy = 0;
-
- if (targetBottom > paddedBottom) {
- scrollBy = targetBottom - paddedBottom;
- }
- if (targetTop < paddedTop) {
- scrollBy = targetTop - paddedTop;
- }
-
- if (scrollBy == 0) {
- return;
- }
-
- if (boundPos >= 0) {
- final View boundChild = getChildAt(boundPos - firstPos);
- final int boundTop = boundChild.getTop();
- final int boundBottom = boundChild.getBottom();
- final int absScroll = Math.abs(scrollBy);
-
- if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) {
- // Don't scroll the bound view off the bottom of the screen.
- scrollBy = Math.max(0, boundBottom - paddedBottom);
- } else if (scrollBy > 0 && boundTop - absScroll < paddedTop) {
- // Don't scroll the bound view off the top of the screen.
- scrollBy = Math.min(0, boundTop - paddedTop);
- }
- }
-
- smoothScrollBy(scrollBy, duration);
- }
-
- void stop() {
- removeCallbacks(this);
- }
-
- @Override
- public void run() {
- final int listHeight = getHeight();
- final int firstPos = mFirstPosition;
-
- switch (mMode) {
- case MOVE_DOWN_POS: {
- final int lastViewIndex = getChildCount() - 1;
- final int lastPos = firstPos + lastViewIndex;
-
- if (lastViewIndex < 0) {
- return;
- }
-
- if (lastPos == mLastSeenPos) {
- // No new views, let things keep going.
- postOnAnimation(this);
- return;
- }
-
- final View lastView = getChildAt(lastViewIndex);
- final int lastViewHeight = lastView.getHeight();
- final int lastViewTop = lastView.getTop();
- final int lastViewPixelsShowing = listHeight - lastViewTop;
- final int extraScroll = lastPos < mItemCount - 1 ?
- Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom;
-
- final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll;
- smoothScrollBy(scrollBy, mScrollDuration, true);
-
- mLastSeenPos = lastPos;
- if (lastPos < mTargetPos) {
- postOnAnimation(this);
- }
- break;
- }
-
- case MOVE_DOWN_BOUND: {
- final int nextViewIndex = 1;
- final int childCount = getChildCount();
-
- if (firstPos == mBoundPos || childCount <= nextViewIndex
- || firstPos + childCount >= mItemCount) {
- return;
- }
- final int nextPos = firstPos + nextViewIndex;
-
- if (nextPos == mLastSeenPos) {
- // No new views, let things keep going.
- postOnAnimation(this);
- return;
- }
-
- final View nextView = getChildAt(nextViewIndex);
- final int nextViewHeight = nextView.getHeight();
- final int nextViewTop = nextView.getTop();
- final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll);
- if (nextPos < mBoundPos) {
- smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll),
- mScrollDuration, true);
-
- mLastSeenPos = nextPos;
-
- postOnAnimation(this);
- } else {
- if (nextViewTop > extraScroll) {
- smoothScrollBy(nextViewTop - extraScroll, mScrollDuration, true);
- }
- }
- break;
- }
-
- case MOVE_UP_POS: {
- if (firstPos == mLastSeenPos) {
- // No new views, let things keep going.
- postOnAnimation(this);
- return;
- }
-
- final View firstView = getChildAt(0);
- if (firstView == null) {
- return;
- }
- final int firstViewTop = firstView.getTop();
- final int extraScroll = firstPos > 0 ?
- Math.max(mExtraScroll, mListPadding.top) : mListPadding.top;
-
- smoothScrollBy(firstViewTop - extraScroll, mScrollDuration, true);
-
- mLastSeenPos = firstPos;
-
- if (firstPos > mTargetPos) {
- postOnAnimation(this);
- }
- break;
- }
-
- case MOVE_UP_BOUND: {
- final int lastViewIndex = getChildCount() - 2;
- if (lastViewIndex < 0) {
- return;
- }
- final int lastPos = firstPos + lastViewIndex;
-
- if (lastPos == mLastSeenPos) {
- // No new views, let things keep going.
- postOnAnimation(this);
- return;
- }
-
- final View lastView = getChildAt(lastViewIndex);
- final int lastViewHeight = lastView.getHeight();
- final int lastViewTop = lastView.getTop();
- final int lastViewPixelsShowing = listHeight - lastViewTop;
- final int extraScroll = Math.max(mListPadding.top, mExtraScroll);
- mLastSeenPos = lastPos;
- if (lastPos > mBoundPos) {
- smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration, true);
- postOnAnimation(this);
- } else {
- final int bottom = listHeight - extraScroll;
- final int lastViewBottom = lastViewTop + lastViewHeight;
- if (bottom > lastViewBottom) {
- smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration, true);
- }
- }
- break;
- }
-
- case MOVE_OFFSET: {
- if (mLastSeenPos == firstPos) {
- // No new views, let things keep going.
- postOnAnimation(this);
- return;
- }
-
- mLastSeenPos = firstPos;
-
- final int childCount = getChildCount();
- final int position = mTargetPos;
- final int lastPos = firstPos + childCount - 1;
-
- int viewTravelCount = 0;
- if (position < firstPos) {
- viewTravelCount = firstPos - position + 1;
- } else if (position > lastPos) {
- viewTravelCount = position - lastPos;
- }
-
- // Estimate how many screens we should travel
- final float screenTravelCount = (float) viewTravelCount / childCount;
-
- final float modifier = Math.min(Math.abs(screenTravelCount), 1.f);
- if (position < firstPos) {
- final int distance = (int) (-getHeight() * modifier);
- final int duration = (int) (mScrollDuration * modifier);
- smoothScrollBy(distance, duration, true);
- postOnAnimation(this);
- } else if (position > lastPos) {
- final int distance = (int) (getHeight() * modifier);
- final int duration = (int) (mScrollDuration * modifier);
- smoothScrollBy(distance, duration, true);
- postOnAnimation(this);
- } else {
- // On-screen, just scroll.
- final int targetTop = getChildAt(position - firstPos).getTop();
- final int distance = targetTop - mOffsetFromTop;
- final int duration = (int) (mScrollDuration *
- ((float) Math.abs(distance) / getHeight()));
- smoothScrollBy(distance, duration, true);
- }
- break;
- }
-
- default:
- break;
- }
- }
- }
-
/**
* The amount of friction applied to flings. The default value
* is {@link ViewConfiguration#getScrollFriction}.
@@ -4834,20 +4412,27 @@
}
/**
+ * Override this for better control over position scrolling.
+ */
+ AbsPositionScroller createPositionScroller() {
+ return new PositionScroller();
+ }
+
+ /**
* Smoothly scroll to the specified adapter position. The view will
* scroll such that the indicated position is displayed.
* @param position Scroll to this adapter position.
*/
public void smoothScrollToPosition(int position) {
if (mPositionScroller == null) {
- mPositionScroller = new PositionScroller();
+ mPositionScroller = createPositionScroller();
}
mPositionScroller.start(position);
}
/**
* Smoothly scroll to the specified adapter position. The view will scroll
- * such that the indicated position is displayed <code>offset</code> pixels from
+ * such that the indicated position is displayed <code>offset</code> pixels below
* the top edge of the view. If this is impossible, (e.g. the offset would scroll
* the first or last item beyond the boundaries of the list) it will get as close
* as possible. The scroll will take <code>duration</code> milliseconds to complete.
@@ -4859,14 +4444,14 @@
*/
public void smoothScrollToPositionFromTop(int position, int offset, int duration) {
if (mPositionScroller == null) {
- mPositionScroller = new PositionScroller();
+ mPositionScroller = createPositionScroller();
}
mPositionScroller.startWithOffset(position, offset, duration);
}
/**
* Smoothly scroll to the specified adapter position. The view will scroll
- * such that the indicated position is displayed <code>offset</code> pixels from
+ * such that the indicated position is displayed <code>offset</code> pixels below
* the top edge of the view. If this is impossible, (e.g. the offset would scroll
* the first or last item beyond the boundaries of the list) it will get as close
* as possible.
@@ -4877,9 +4462,9 @@
*/
public void smoothScrollToPositionFromTop(int position, int offset) {
if (mPositionScroller == null) {
- mPositionScroller = new PositionScroller();
+ mPositionScroller = createPositionScroller();
}
- mPositionScroller.startWithOffset(position, offset);
+ mPositionScroller.startWithOffset(position, offset, offset);
}
/**
@@ -4893,7 +4478,7 @@
*/
public void smoothScrollToPosition(int position, int boundPosition) {
if (mPositionScroller == null) {
- mPositionScroller = new PositionScroller();
+ mPositionScroller = createPositionScroller();
}
mPositionScroller.start(position, boundPosition);
}
@@ -6605,18 +6190,12 @@
void clear() {
if (mViewTypeCount == 1) {
final ArrayList<View> scrap = mCurrentScrap;
- final int scrapCount = scrap.size();
- for (int i = 0; i < scrapCount; i++) {
- removeDetachedView(scrap.remove(scrapCount - 1 - i), false);
- }
+ clearScrap(scrap);
} else {
final int typeCount = mViewTypeCount;
for (int i = 0; i < typeCount; i++) {
final ArrayList<View> scrap = mScrapViews[i];
- final int scrapCount = scrap.size();
- for (int j = 0; j < scrapCount; j++) {
- removeDetachedView(scrap.remove(scrapCount - 1 - j), false);
- }
+ clearScrap(scrap);
}
}
@@ -6717,7 +6296,7 @@
if (mViewTypeCount == 1) {
return retrieveFromScrap(mCurrentScrap, position);
} else {
- int whichScrap = mAdapter.getItemViewType(position);
+ final int whichScrap = mAdapter.getItemViewType(position);
if (whichScrap >= 0 && whichScrap < mScrapViews.length) {
return retrieveFromScrap(mScrapViews[whichScrap], position);
}
@@ -6789,13 +6368,6 @@
mScrapViews[viewType].add(scrap);
}
- // Clear any system-managed transient state.
- if (scrap.isAccessibilityFocused()) {
- scrap.clearAccessibilityFocus();
- }
-
- scrap.setAccessibilityDelegate(null);
-
if (mRecyclerListener != null) {
mRecyclerListener.onMovedToScrapHeap(scrap);
}
@@ -6869,7 +6441,6 @@
lp.scrappedFromPosition = mFirstActivePosition + i;
scrapViews.add(victim);
- victim.setAccessibilityDelegate(null);
if (hasListener) {
mRecyclerListener.onMovedToScrapHeap(victim);
}
@@ -6973,23 +6544,853 @@
}
}
}
+
+ private View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
+ final int size = scrapViews.size();
+ if (size > 0) {
+ // See if we still have a view for this position or ID.
+ for (int i = 0; i < size; i++) {
+ final View view = scrapViews.get(i);
+ final AbsListView.LayoutParams params =
+ (AbsListView.LayoutParams) view.getLayoutParams();
+
+ if (mAdapterHasStableIds) {
+ final long id = mAdapter.getItemId(position);
+ if (id == params.itemId) {
+ return scrapViews.remove(i);
+ }
+ } else if (params.scrappedFromPosition == position) {
+ final View scrap = scrapViews.remove(i);
+ clearAccessibilityFromScrap(scrap);
+ return scrap;
+ }
+ }
+ final View scrap = scrapViews.remove(size - 1);
+ clearAccessibilityFromScrap(scrap);
+ return scrap;
+ } else {
+ return null;
+ }
+ }
+
+ private void clearScrap(final ArrayList<View> scrap) {
+ final int scrapCount = scrap.size();
+ for (int j = 0; j < scrapCount; j++) {
+ removeDetachedView(scrap.remove(scrapCount - 1 - j), false);
+ }
+ }
+
+ private void clearAccessibilityFromScrap(View view) {
+ if (view.isAccessibilityFocused()) {
+ view.clearAccessibilityFocus();
+ }
+ view.setAccessibilityDelegate(null);
+ }
+
+ private void removeDetachedView(View child, boolean animate) {
+ child.setAccessibilityDelegate(null);
+ AbsListView.this.removeDetachedView(child, animate);
+ }
}
- static View retrieveFromScrap(ArrayList<View> scrapViews, int position) {
- int size = scrapViews.size();
- if (size > 0) {
- // See if we still have a view for this position.
- for (int i=0; i<size; i++) {
- View view = scrapViews.get(i);
- if (((AbsListView.LayoutParams)view.getLayoutParams())
- .scrappedFromPosition == position) {
- scrapViews.remove(i);
- return view;
+ /**
+ * Returns the height of the view for the specified position.
+ *
+ * @param position the item position
+ * @return view height in pixels
+ */
+ int getHeightForPosition(int position) {
+ final int firstVisiblePosition = getFirstVisiblePosition();
+ final int childCount = getChildCount();
+ final int index = position - firstVisiblePosition;
+ if (index >= 0 && index < childCount) {
+ // Position is on-screen, use existing view.
+ final View view = getChildAt(index);
+ return view.getHeight();
+ } else {
+ // Position is off-screen, obtain & recycle view.
+ final View view = obtainView(position, mIsScrap);
+ view.measure(mWidthMeasureSpec, MeasureSpec.UNSPECIFIED);
+ final int height = view.getMeasuredHeight();
+ mRecycler.addScrapView(view, position);
+ return height;
+ }
+ }
+
+ /**
+ * Sets the selected item and positions the selection y pixels from the top edge
+ * of the ListView. (If in touch mode, the item will not be selected but it will
+ * still be positioned appropriately.)
+ *
+ * @param position Index (starting at 0) of the data item to be selected.
+ * @param y The distance from the top edge of the ListView (plus padding) that the
+ * item will be positioned.
+ */
+ public void setSelectionFromTop(int position, int y) {
+ if (mAdapter == null) {
+ return;
+ }
+
+ if (!isInTouchMode()) {
+ position = lookForSelectablePosition(position, true);
+ if (position >= 0) {
+ setNextSelectedPositionInt(position);
+ }
+ } else {
+ mResurrectToPosition = position;
+ }
+
+ if (position >= 0) {
+ mLayoutMode = LAYOUT_SPECIFIC;
+ mSpecificTop = mListPadding.top + y;
+
+ if (mNeedSync) {
+ mSyncPosition = position;
+ mSyncRowId = mAdapter.getItemId(position);
+ }
+
+ if (mPositionScroller != null) {
+ mPositionScroller.stop();
+ }
+ requestLayout();
+ }
+ }
+
+ /**
+ * Abstract positon scroller used to handle smooth scrolling.
+ */
+ static abstract class AbsPositionScroller {
+ public abstract void start(int position);
+ public abstract void start(int position, int boundPosition);
+ public abstract void startWithOffset(int position, int offset);
+ public abstract void startWithOffset(int position, int offset, int duration);
+ public abstract void stop();
+ }
+
+ /**
+ * Default position scroller that simulates a fling.
+ */
+ class PositionScroller extends AbsPositionScroller implements Runnable {
+ private static final int SCROLL_DURATION = 200;
+
+ private static final int MOVE_DOWN_POS = 1;
+ private static final int MOVE_UP_POS = 2;
+ private static final int MOVE_DOWN_BOUND = 3;
+ private static final int MOVE_UP_BOUND = 4;
+ private static final int MOVE_OFFSET = 5;
+
+ private int mMode;
+ private int mTargetPos;
+ private int mBoundPos;
+ private int mLastSeenPos;
+ private int mScrollDuration;
+ private final int mExtraScroll;
+
+ private int mOffsetFromTop;
+
+ PositionScroller() {
+ mExtraScroll = ViewConfiguration.get(mContext).getScaledFadingEdgeLength();
+ }
+
+ @Override
+ public void start(final int position) {
+ stop();
+
+ if (mDataChanged) {
+ // Wait until we're back in a stable state to try this.
+ mPositionScrollAfterLayout = new Runnable() {
+ @Override public void run() {
+ start(position);
+ }
+ };
+ return;
+ }
+
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Can't scroll without children.
+ return;
+ }
+
+ final int firstPos = mFirstPosition;
+ final int lastPos = firstPos + childCount - 1;
+
+ int viewTravelCount;
+ int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
+ if (clampedPosition < firstPos) {
+ viewTravelCount = firstPos - clampedPosition + 1;
+ mMode = MOVE_UP_POS;
+ } else if (clampedPosition > lastPos) {
+ viewTravelCount = clampedPosition - lastPos + 1;
+ mMode = MOVE_DOWN_POS;
+ } else {
+ scrollToVisible(clampedPosition, INVALID_POSITION, SCROLL_DURATION);
+ return;
+ }
+
+ if (viewTravelCount > 0) {
+ mScrollDuration = SCROLL_DURATION / viewTravelCount;
+ } else {
+ mScrollDuration = SCROLL_DURATION;
+ }
+ mTargetPos = clampedPosition;
+ mBoundPos = INVALID_POSITION;
+ mLastSeenPos = INVALID_POSITION;
+
+ postOnAnimation(this);
+ }
+
+ @Override
+ public void start(final int position, final int boundPosition) {
+ stop();
+
+ if (boundPosition == INVALID_POSITION) {
+ start(position);
+ return;
+ }
+
+ if (mDataChanged) {
+ // Wait until we're back in a stable state to try this.
+ mPositionScrollAfterLayout = new Runnable() {
+ @Override public void run() {
+ start(position, boundPosition);
+ }
+ };
+ return;
+ }
+
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Can't scroll without children.
+ return;
+ }
+
+ final int firstPos = mFirstPosition;
+ final int lastPos = firstPos + childCount - 1;
+
+ int viewTravelCount;
+ int clampedPosition = Math.max(0, Math.min(getCount() - 1, position));
+ if (clampedPosition < firstPos) {
+ final int boundPosFromLast = lastPos - boundPosition;
+ if (boundPosFromLast < 1) {
+ // Moving would shift our bound position off the screen. Abort.
+ return;
+ }
+
+ final int posTravel = firstPos - clampedPosition + 1;
+ final int boundTravel = boundPosFromLast - 1;
+ if (boundTravel < posTravel) {
+ viewTravelCount = boundTravel;
+ mMode = MOVE_UP_BOUND;
+ } else {
+ viewTravelCount = posTravel;
+ mMode = MOVE_UP_POS;
+ }
+ } else if (clampedPosition > lastPos) {
+ final int boundPosFromFirst = boundPosition - firstPos;
+ if (boundPosFromFirst < 1) {
+ // Moving would shift our bound position off the screen. Abort.
+ return;
+ }
+
+ final int posTravel = clampedPosition - lastPos + 1;
+ final int boundTravel = boundPosFromFirst - 1;
+ if (boundTravel < posTravel) {
+ viewTravelCount = boundTravel;
+ mMode = MOVE_DOWN_BOUND;
+ } else {
+ viewTravelCount = posTravel;
+ mMode = MOVE_DOWN_POS;
+ }
+ } else {
+ scrollToVisible(clampedPosition, boundPosition, SCROLL_DURATION);
+ return;
+ }
+
+ if (viewTravelCount > 0) {
+ mScrollDuration = SCROLL_DURATION / viewTravelCount;
+ } else {
+ mScrollDuration = SCROLL_DURATION;
+ }
+ mTargetPos = clampedPosition;
+ mBoundPos = boundPosition;
+ mLastSeenPos = INVALID_POSITION;
+
+ postOnAnimation(this);
+ }
+
+ @Override
+ public void startWithOffset(int position, int offset) {
+ startWithOffset(position, offset, SCROLL_DURATION);
+ }
+
+ @Override
+ public void startWithOffset(final int position, int offset, final int duration) {
+ stop();
+
+ if (mDataChanged) {
+ // Wait until we're back in a stable state to try this.
+ final int postOffset = offset;
+ mPositionScrollAfterLayout = new Runnable() {
+ @Override public void run() {
+ startWithOffset(position, postOffset, duration);
+ }
+ };
+ return;
+ }
+
+ final int childCount = getChildCount();
+ if (childCount == 0) {
+ // Can't scroll without children.
+ return;
+ }
+
+ offset += getPaddingTop();
+
+ mTargetPos = Math.max(0, Math.min(getCount() - 1, position));
+ mOffsetFromTop = offset;
+ mBoundPos = INVALID_POSITION;
+ mLastSeenPos = INVALID_POSITION;
+ mMode = MOVE_OFFSET;
+
+ final int firstPos = mFirstPosition;
+ final int lastPos = firstPos + childCount - 1;
+
+ int viewTravelCount;
+ if (mTargetPos < firstPos) {
+ viewTravelCount = firstPos - mTargetPos;
+ } else if (mTargetPos > lastPos) {
+ viewTravelCount = mTargetPos - lastPos;
+ } else {
+ // On-screen, just scroll.
+ final int targetTop = getChildAt(mTargetPos - firstPos).getTop();
+ smoothScrollBy(targetTop - offset, duration, true);
+ return;
+ }
+
+ // Estimate how many screens we should travel
+ final float screenTravelCount = (float) viewTravelCount / childCount;
+ mScrollDuration = screenTravelCount < 1 ?
+ duration : (int) (duration / screenTravelCount);
+ mLastSeenPos = INVALID_POSITION;
+
+ postOnAnimation(this);
+ }
+
+ /**
+ * Scroll such that targetPos is in the visible padded region without scrolling
+ * boundPos out of view. Assumes targetPos is onscreen.
+ */
+ private void scrollToVisible(int targetPos, int boundPos, int duration) {
+ final int firstPos = mFirstPosition;
+ final int childCount = getChildCount();
+ final int lastPos = firstPos + childCount - 1;
+ final int paddedTop = mListPadding.top;
+ final int paddedBottom = getHeight() - mListPadding.bottom;
+
+ if (targetPos < firstPos || targetPos > lastPos) {
+ Log.w(TAG, "scrollToVisible called with targetPos " + targetPos +
+ " not visible [" + firstPos + ", " + lastPos + "]");
+ }
+ if (boundPos < firstPos || boundPos > lastPos) {
+ // boundPos doesn't matter, it's already offscreen.
+ boundPos = INVALID_POSITION;
+ }
+
+ final View targetChild = getChildAt(targetPos - firstPos);
+ final int targetTop = targetChild.getTop();
+ final int targetBottom = targetChild.getBottom();
+ int scrollBy = 0;
+
+ if (targetBottom > paddedBottom) {
+ scrollBy = targetBottom - paddedBottom;
+ }
+ if (targetTop < paddedTop) {
+ scrollBy = targetTop - paddedTop;
+ }
+
+ if (scrollBy == 0) {
+ return;
+ }
+
+ if (boundPos >= 0) {
+ final View boundChild = getChildAt(boundPos - firstPos);
+ final int boundTop = boundChild.getTop();
+ final int boundBottom = boundChild.getBottom();
+ final int absScroll = Math.abs(scrollBy);
+
+ if (scrollBy < 0 && boundBottom + absScroll > paddedBottom) {
+ // Don't scroll the bound view off the bottom of the screen.
+ scrollBy = Math.max(0, boundBottom - paddedBottom);
+ } else if (scrollBy > 0 && boundTop - absScroll < paddedTop) {
+ // Don't scroll the bound view off the top of the screen.
+ scrollBy = Math.min(0, boundTop - paddedTop);
}
}
- return scrapViews.remove(size - 1);
- } else {
- return null;
+
+ smoothScrollBy(scrollBy, duration);
+ }
+
+ @Override
+ public void stop() {
+ removeCallbacks(this);
+ }
+
+ @Override
+ public void run() {
+ final int listHeight = getHeight();
+ final int firstPos = mFirstPosition;
+
+ switch (mMode) {
+ case MOVE_DOWN_POS: {
+ final int lastViewIndex = getChildCount() - 1;
+ final int lastPos = firstPos + lastViewIndex;
+
+ if (lastViewIndex < 0) {
+ return;
+ }
+
+ if (lastPos == mLastSeenPos) {
+ // No new views, let things keep going.
+ postOnAnimation(this);
+ return;
+ }
+
+ final View lastView = getChildAt(lastViewIndex);
+ final int lastViewHeight = lastView.getHeight();
+ final int lastViewTop = lastView.getTop();
+ final int lastViewPixelsShowing = listHeight - lastViewTop;
+ final int extraScroll = lastPos < mItemCount - 1 ?
+ Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom;
+
+ final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll;
+ smoothScrollBy(scrollBy, mScrollDuration, true);
+
+ mLastSeenPos = lastPos;
+ if (lastPos < mTargetPos) {
+ postOnAnimation(this);
+ }
+ break;
+ }
+
+ case MOVE_DOWN_BOUND: {
+ final int nextViewIndex = 1;
+ final int childCount = getChildCount();
+
+ if (firstPos == mBoundPos || childCount <= nextViewIndex
+ || firstPos + childCount >= mItemCount) {
+ return;
+ }
+ final int nextPos = firstPos + nextViewIndex;
+
+ if (nextPos == mLastSeenPos) {
+ // No new views, let things keep going.
+ postOnAnimation(this);
+ return;
+ }
+
+ final View nextView = getChildAt(nextViewIndex);
+ final int nextViewHeight = nextView.getHeight();
+ final int nextViewTop = nextView.getTop();
+ final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll);
+ if (nextPos < mBoundPos) {
+ smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll),
+ mScrollDuration, true);
+
+ mLastSeenPos = nextPos;
+
+ postOnAnimation(this);
+ } else {
+ if (nextViewTop > extraScroll) {
+ smoothScrollBy(nextViewTop - extraScroll, mScrollDuration, true);
+ }
+ }
+ break;
+ }
+
+ case MOVE_UP_POS: {
+ if (firstPos == mLastSeenPos) {
+ // No new views, let things keep going.
+ postOnAnimation(this);
+ return;
+ }
+
+ final View firstView = getChildAt(0);
+ if (firstView == null) {
+ return;
+ }
+ final int firstViewTop = firstView.getTop();
+ final int extraScroll = firstPos > 0 ?
+ Math.max(mExtraScroll, mListPadding.top) : mListPadding.top;
+
+ smoothScrollBy(firstViewTop - extraScroll, mScrollDuration, true);
+
+ mLastSeenPos = firstPos;
+
+ if (firstPos > mTargetPos) {
+ postOnAnimation(this);
+ }
+ break;
+ }
+
+ case MOVE_UP_BOUND: {
+ final int lastViewIndex = getChildCount() - 2;
+ if (lastViewIndex < 0) {
+ return;
+ }
+ final int lastPos = firstPos + lastViewIndex;
+
+ if (lastPos == mLastSeenPos) {
+ // No new views, let things keep going.
+ postOnAnimation(this);
+ return;
+ }
+
+ final View lastView = getChildAt(lastViewIndex);
+ final int lastViewHeight = lastView.getHeight();
+ final int lastViewTop = lastView.getTop();
+ final int lastViewPixelsShowing = listHeight - lastViewTop;
+ final int extraScroll = Math.max(mListPadding.top, mExtraScroll);
+ mLastSeenPos = lastPos;
+ if (lastPos > mBoundPos) {
+ smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration, true);
+ postOnAnimation(this);
+ } else {
+ final int bottom = listHeight - extraScroll;
+ final int lastViewBottom = lastViewTop + lastViewHeight;
+ if (bottom > lastViewBottom) {
+ smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration, true);
+ }
+ }
+ break;
+ }
+
+ case MOVE_OFFSET: {
+ if (mLastSeenPos == firstPos) {
+ // No new views, let things keep going.
+ postOnAnimation(this);
+ return;
+ }
+
+ mLastSeenPos = firstPos;
+
+ final int childCount = getChildCount();
+ final int position = mTargetPos;
+ final int lastPos = firstPos + childCount - 1;
+
+ int viewTravelCount = 0;
+ if (position < firstPos) {
+ viewTravelCount = firstPos - position + 1;
+ } else if (position > lastPos) {
+ viewTravelCount = position - lastPos;
+ }
+
+ // Estimate how many screens we should travel
+ final float screenTravelCount = (float) viewTravelCount / childCount;
+
+ final float modifier = Math.min(Math.abs(screenTravelCount), 1.f);
+ if (position < firstPos) {
+ final int distance = (int) (-getHeight() * modifier);
+ final int duration = (int) (mScrollDuration * modifier);
+ smoothScrollBy(distance, duration, true);
+ postOnAnimation(this);
+ } else if (position > lastPos) {
+ final int distance = (int) (getHeight() * modifier);
+ final int duration = (int) (mScrollDuration * modifier);
+ smoothScrollBy(distance, duration, true);
+ postOnAnimation(this);
+ } else {
+ // On-screen, just scroll.
+ final int targetTop = getChildAt(position - firstPos).getTop();
+ final int distance = targetTop - mOffsetFromTop;
+ final int duration = (int) (mScrollDuration *
+ ((float) Math.abs(distance) / getHeight()));
+ smoothScrollBy(distance, duration, true);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Abstract position scroller that handles sub-position scrolling but has no
+ * understanding of layout.
+ */
+ abstract class AbsSubPositionScroller extends AbsPositionScroller {
+ private static final int DEFAULT_SCROLL_DURATION = 200;
+
+ private final SubScroller mSubScroller = new SubScroller();
+
+ /**
+ * The target offset in pixels between the top of the list and the top
+ * of the target position.
+ */
+ private int mOffset;
+
+ /**
+ * Scroll the minimum amount to get the target view entirely on-screen.
+ */
+ private void scrollToPosition(final int targetPosition, final boolean useOffset,
+ final int offset, final int boundPosition, final int duration) {
+ stop();
+
+ if (mDataChanged) {
+ // Wait until we're back in a stable state to try this.
+ mPositionScrollAfterLayout = new Runnable() {
+ @Override
+ public void run() {
+ scrollToPosition(
+ targetPosition, useOffset, offset, boundPosition, duration);
+ }
+ };
+ return;
+ }
+
+ final int firstPosition = getFirstVisiblePosition();
+ final int lastPosition = firstPosition + getChildCount();
+ final int targetRow = getRowForPosition(targetPosition);
+ final int firstRow = getRowForPosition(firstPosition);
+ final int lastRow = getRowForPosition(lastPosition);
+ if (useOffset || targetRow <= firstRow) {
+ // Offset so the target row is top-aligned.
+ mOffset = offset;
+ } else if (targetRow >= lastRow - 1) {
+ // Offset so the target row is bottom-aligned.
+ final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
+ mOffset = listHeight - getHeightForPosition(targetPosition);
+ } else {
+ // Don't scroll, target is entirely on-screen.
+ return;
+ }
+
+ float endSubRow = targetRow;
+ if (boundPosition != INVALID_POSITION) {
+ final int boundRow = getRowForPosition(boundPosition);
+ if (boundRow >= firstRow && boundRow < lastRow && boundRow != targetRow) {
+ endSubRow = computeBoundSubRow(targetRow, boundRow);
+ }
+ }
+
+ final View firstChild = getChildAt(0);
+ if (firstChild == null) {
+ return;
+ }
+
+ final int firstChildHeight = firstChild.getHeight();
+ final float startOffsetRatio;
+ if (firstChildHeight == 0) {
+ startOffsetRatio = 1;
+ } else {
+ startOffsetRatio = -firstChild.getTop() / (float) firstChildHeight;
+ }
+
+ final float startSubRow = firstRow + startOffsetRatio;
+ if (startSubRow == endSubRow && mOffset == 0) {
+ // Don't scroll, target is already in position.
+ return;
+ }
+
+ mSubScroller.startScroll(startSubRow, endSubRow, duration);
+
+ postOnAnimation(mAnimationFrame);
+ }
+
+ private float computeBoundSubRow(int targetRow, int boundRow) {
+ // If the final offset is greater than 0, we're aiming above the
+ // suggested target row. Compute the actual target row and offset
+ // within that row by subtracting the height of each preceeding row.
+ int remainingOffset = mOffset;
+ int targetHeight = getHeightForRow(targetRow);
+ while (targetRow > 1 && remainingOffset > targetHeight) {
+ targetRow--;
+ remainingOffset -= targetHeight;
+ targetHeight = getHeightForRow(targetRow);
+ }
+
+ // Compute the offset within the actual target row.
+ final float targetOffsetRatio;
+ if (remainingOffset > 0) {
+ // We can't reach that offset given the row count.
+ targetOffsetRatio = 0;
+ } else if (targetHeight == 0) {
+ targetOffsetRatio = 1;
+ } else {
+ targetOffsetRatio = remainingOffset / (float) targetHeight;
+ }
+
+ // The final offset has been accounted for, reset it.
+ final float targetSubRow = targetRow - targetOffsetRatio;
+ mOffset = 0;
+
+ if (targetSubRow >= boundRow) {
+ // End position would push the bound position above the list.
+ return boundRow;
+ }
+
+ // Compute the closest possible sub-position that wouldn't push the
+ // bound position's view further below the list.
+ final int listHeight = getHeight() - getPaddingTop() - getPaddingBottom();
+ final int boundHeight = getHeightForRow(boundRow);
+ int endRow = boundRow;
+ int totalHeight = boundHeight;
+ int endHeight;
+ do {
+ endRow--;
+ endHeight = getHeightForRow(endRow);
+ totalHeight += endHeight;
+ } while (totalHeight < listHeight && endRow > 0);
+
+ final float endOffsetRatio;
+ if (endHeight == 0) {
+ endOffsetRatio = 1;
+ } else {
+ endOffsetRatio = (totalHeight - listHeight) / (float) endHeight;
+ }
+
+ final float boundSubRow = endRow + endOffsetRatio;
+ return Math.max(boundSubRow, targetSubRow);
+ }
+
+ @Override
+ public void start(int position) {
+ scrollToPosition(position, false, 0, INVALID_POSITION, DEFAULT_SCROLL_DURATION);
+ }
+
+ @Override
+ public void start(int position, int boundPosition) {
+ scrollToPosition(position, false, 0, boundPosition, DEFAULT_SCROLL_DURATION);
+ }
+
+ @Override
+ public void startWithOffset(int position, int offset) {
+ scrollToPosition(position, true, offset, INVALID_POSITION, DEFAULT_SCROLL_DURATION);
+ }
+
+ @Override
+ public void startWithOffset(int position, int offset, int duration) {
+ scrollToPosition(position, true, offset, INVALID_POSITION, duration);
+ }
+
+ @Override
+ public void stop() {
+ removeCallbacks(mAnimationFrame);
+ }
+
+ /**
+ * Returns the height of a row, which is computed as the maximum height of
+ * the items in the row.
+ *
+ * @param row the row index
+ * @return row height in pixels
+ */
+ public abstract int getHeightForRow(int row);
+
+ /**
+ * Returns the row for the specified item position.
+ *
+ * @param position the item position
+ * @return the row index
+ */
+ public abstract int getRowForPosition(int position);
+
+ /**
+ * Returns the first item position within the specified row.
+ *
+ * @param row the row
+ * @return the position of the first item in the row
+ */
+ public abstract int getFirstPositionForRow(int row);
+
+ private void onAnimationFrame() {
+ final boolean shouldPost = mSubScroller.computePosition();
+ final float subRow = mSubScroller.getPosition();
+
+ final int row = (int) subRow;
+ final int position = getFirstPositionForRow(row);
+ if (position >= getCount()) {
+ // Invalid position, abort scrolling.
+ return;
+ }
+
+ final int rowHeight = getHeightForRow(row);
+ final int offset = (int) (rowHeight * (subRow - row));
+ final int addOffset = (int) (mOffset * mSubScroller.getInterpolatedValue());
+ setSelectionFromTop(position, -offset + addOffset);
+
+ if (shouldPost) {
+ postOnAnimation(mAnimationFrame);
+ }
+ }
+
+ private Runnable mAnimationFrame = new Runnable() {
+ @Override
+ public void run() {
+ onAnimationFrame();
+ }
+ };
+ }
+
+ /**
+ * Scroller capable of returning floating point positions.
+ */
+ static class SubScroller {
+ private final Interpolator mInterpolator;
+
+ private float mStartPosition;
+ private float mEndPosition;
+ private long mStartTime;
+ private long mDuration;
+
+ private float mPosition;
+ private float mInterpolatedValue;
+
+ public SubScroller() {
+ this(null);
+ }
+
+ public SubScroller(Interpolator interpolator) {
+ if (interpolator == null) {
+ mInterpolator = new AccelerateDecelerateInterpolator();
+ } else {
+ mInterpolator = interpolator;
+ }
+ }
+
+ public void startScroll(float startPosition, float endPosition, int duration) {
+ mStartPosition = startPosition;
+ mEndPosition = endPosition;
+ mDuration = duration;
+
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mPosition = startPosition;
+ mInterpolatedValue = 0;
+ }
+
+ public boolean computePosition() {
+ final long elapsed = AnimationUtils.currentAnimationTimeMillis() - mStartTime;
+ final float value;
+ if (mDuration <= 0) {
+ value = 1;
+ } else {
+ value = MathUtils.constrain(elapsed / (float) mDuration, 0, 1);
+ }
+
+ mInterpolatedValue = mInterpolator.getInterpolation(value);
+ mPosition = (mEndPosition - mStartPosition) * mInterpolatedValue + mStartPosition;
+
+ return elapsed < mDuration;
+ }
+
+ public float getPosition() {
+ return mPosition;
+ }
+
+ public float getInterpolatedValue() {
+ return mInterpolatedValue;
}
}
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 962ffba..1da22ca 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -667,7 +667,7 @@
/**
* When the current adapter is empty, the AdapterView can display a special view
- * call the empty view. The empty view is used to provide feedback to the user
+ * called the empty view. The empty view is used to provide feedback to the user
* that no data is available in this AdapterView.
*
* @return The view to show if the adapter is empty.
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 3a7cc87..a8ff562 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,6 +17,7 @@
package android.widget;
import android.content.Context;
+import android.os.Bundle;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
@@ -132,4 +133,22 @@
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(EditText.class.getName());
}
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_SET_TEXT: {
+ CharSequence text = (arguments != null) ? arguments.getCharSequence(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE) : null;
+ setText(text);
+ if (text != null && text.length() > 0) {
+ setSelection(text.length());
+ }
+ return true;
+ }
+ default: {
+ return super.performAccessibilityAction(action, arguments);
+ }
+ }
+ }
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index acd711d..04b18c1 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -30,8 +30,10 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
import android.view.animation.GridLayoutAnimationController;
@@ -1027,6 +1029,11 @@
}
@Override
+ AbsPositionScroller createPositionScroller() {
+ return new GridViewPositionScroller();
+ }
+
+ @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Sets up mListPadding
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -1215,22 +1222,32 @@
setSelectedPositionInt(mNextSelectedPosition);
- // Remember which child, if any, had accessibility focus.
- final int accessibilityFocusPosition;
- final View accessFocusedChild = getAccessibilityFocusedChild();
- if (accessFocusedChild != null) {
- accessibilityFocusPosition = getPositionForView(accessFocusedChild);
- accessFocusedChild.setHasTransientState(true);
- } else {
- accessibilityFocusPosition = INVALID_POSITION;
- }
+ AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
+ View accessibilityFocusLayoutRestoreView = null;
+ int accessibilityFocusPosition = INVALID_POSITION;
- // Ensure the child containing focus, if any, has transient state.
- // If the list data hasn't changed, or if the adapter has stable
- // IDs, this will maintain focus.
- final View focusedChild = getFocusedChild();
- if (focusedChild != null) {
- focusedChild.setHasTransientState(true);
+ // Remember which child, if any, had accessibility focus. This must
+ // occur before recycling any views, since that will clear
+ // accessibility focus.
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
+ if (focusHost != null) {
+ final View focusChild = getAccessibilityFocusedChild(focusHost);
+ if (focusChild != null) {
+ if (!dataChanged || focusChild.hasTransientState()
+ || mAdapterHasStableIds) {
+ // The views won't be changing, so try to maintain
+ // focus on the current host and virtual view.
+ accessibilityFocusLayoutRestoreView = focusHost;
+ accessibilityFocusLayoutRestoreNode = viewRootImpl
+ .getAccessibilityFocusedVirtualView();
+ }
+
+ // Try to maintain focus at the same position.
+ accessibilityFocusPosition = getPositionForView(focusChild);
+ }
+ }
}
// Pull all children into the RecycleBin.
@@ -1317,27 +1334,35 @@
mSelectorRect.setEmpty();
}
- if (accessFocusedChild != null) {
- accessFocusedChild.setHasTransientState(false);
-
- // If we failed to maintain accessibility focus on the previous
- // view, attempt to restore it to the previous position.
- if (!accessFocusedChild.isAccessibilityFocused()
- && accessibilityFocusPosition != INVALID_POSITION) {
- // Bound the position within the visible children.
- final int position = MathUtils.constrain(
- accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1);
- final View restoreView = getChildAt(position);
- if (restoreView != null) {
- restoreView.requestAccessibilityFocus();
+ // Attempt to restore accessibility focus, if necessary.
+ if (viewRootImpl != null) {
+ final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost();
+ if (newAccessibilityFocusedView == null) {
+ if (accessibilityFocusLayoutRestoreView != null
+ && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) {
+ final AccessibilityNodeProvider provider =
+ accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
+ if (accessibilityFocusLayoutRestoreNode != null && provider != null) {
+ final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
+ accessibilityFocusLayoutRestoreNode.getSourceNodeId());
+ provider.performAction(virtualViewId,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+ } else {
+ accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+ }
+ } else if (accessibilityFocusPosition != INVALID_POSITION) {
+ // Bound the position within the visible children.
+ final int position = MathUtils.constrain(
+ accessibilityFocusPosition - mFirstPosition, 0,
+ getChildCount() - 1);
+ final View restoreView = getChildAt(position);
+ if (restoreView != null) {
+ restoreView.requestAccessibilityFocus();
+ }
}
}
}
- if (focusedChild != null) {
- focusedChild.setHasTransientState(false);
- }
-
mLayoutMode = LAYOUT_NORMAL;
mDataChanged = false;
if (mPositionScrollAfterLayout != null) {
@@ -2317,7 +2342,9 @@
final int columnsCount = getNumColumns();
final int rowsCount = getCount() / columnsCount;
- final CollectionInfo collectionInfo = CollectionInfo.obtain(columnsCount, rowsCount, false);
+ final int selectionMode = getSelectionModeForAccessibility();
+ final CollectionInfo collectionInfo = CollectionInfo.obtain(
+ columnsCount, rowsCount, false, selectionMode);
info.setCollectionInfo(collectionInfo);
}
@@ -2344,7 +2371,38 @@
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
- final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(column, 1, row, 1, isHeading);
+ final boolean isSelected = isItemChecked(position);
+ final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
+ column, 1, row, 1, isHeading, isSelected);
info.setCollectionItemInfo(itemInfo);
}
+
+ /**
+ * Sub-position scroller that understands the layout of a GridView.
+ */
+ class GridViewPositionScroller extends AbsSubPositionScroller {
+ @Override
+ public int getRowForPosition(int position) {
+ return position / mNumColumns;
+ }
+
+ @Override
+ public int getFirstPositionForRow(int row) {
+ return row * mNumColumns;
+ }
+
+ @Override
+ public int getHeightForRow(int row) {
+ final int firstRowPosition = row * mNumColumns;
+ final int lastRowPosition = Math.min(getCount(), firstRowPosition + mNumColumns);
+ int maxHeight = 0;
+ for (int i = firstRowPosition; i < lastRowPosition; i++) {
+ final int height = getHeightForPosition(i);
+ if (height > maxHeight) {
+ maxHeight = height;
+ }
+ }
+ return maxHeight;
+ }
+ }
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 65f1ab7..82e624d 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -667,6 +667,7 @@
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
boolean matchWidth = false;
+ boolean skippedMeasure = false;
final int baselineChildIndex = mBaselineAlignedChildIndex;
final boolean useLargestChild = mUseLargestChild;
@@ -701,6 +702,7 @@
// there is any leftover space.
final int totalLength = mTotalLength;
mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
+ skippedMeasure = true;
} else {
int oldHeight = Integer.MIN_VALUE;
@@ -827,9 +829,10 @@
heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
// Either expand children with weight to take up available space or
- // shrink them if they extend beyond our current bounds
+ // shrink them if they extend beyond our current bounds. If we skipped
+ // measurement on any children, we need to measure them now.
int delta = heightSize - mTotalLength;
- if (delta != 0 && totalWeight > 0.0f) {
+ if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
mTotalLength = 0;
@@ -995,6 +998,7 @@
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
boolean matchHeight = false;
+ boolean skippedMeasure = false;
if (mMaxAscent == null || mMaxDescent == null) {
mMaxAscent = new int[VERTICAL_GRAVITY_COUNT];
@@ -1057,6 +1061,8 @@
if (baselineAligned) {
final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(freeSpec, freeSpec);
+ } else {
+ skippedMeasure = true;
}
} else {
int oldWidth = Integer.MIN_VALUE;
@@ -1205,9 +1211,10 @@
widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
// Either expand children with weight to take up available space or
- // shrink them if they extend beyond our current bounds
+ // shrink them if they extend beyond our current bounds. If we skipped
+ // measurement on any children, we need to measure them now.
int delta = widthSize - mTotalLength;
- if (delta != 0 && totalWeight > 0.0f) {
+ if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c461723..5de67c8 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -39,10 +39,12 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.ViewParent;
+import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
import android.widget.RemoteViews.RemoteView;
import java.util.ArrayList;
@@ -1567,22 +1569,58 @@
setSelectedPositionInt(mNextSelectedPosition);
- // Remember which child, if any, had accessibility focus.
- final int accessibilityFocusPosition;
- final View accessFocusedChild = getAccessibilityFocusedChild();
- if (accessFocusedChild != null) {
- accessibilityFocusPosition = getPositionForView(accessFocusedChild);
- accessFocusedChild.setHasTransientState(true);
- } else {
- accessibilityFocusPosition = INVALID_POSITION;
+ AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
+ View accessibilityFocusLayoutRestoreView = null;
+ int accessibilityFocusPosition = INVALID_POSITION;
+
+ // Remember which child, if any, had accessibility focus. This must
+ // occur before recycling any views, since that will clear
+ // accessibility focus.
+ final ViewRootImpl viewRootImpl = getViewRootImpl();
+ if (viewRootImpl != null) {
+ final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
+ if (focusHost != null) {
+ final View focusChild = getAccessibilityFocusedChild(focusHost);
+ if (focusChild != null) {
+ if (!dataChanged || isDirectChildHeaderOrFooter(focusChild)
+ || focusChild.hasTransientState() || mAdapterHasStableIds) {
+ // The views won't be changing, so try to maintain
+ // focus on the current host and virtual view.
+ accessibilityFocusLayoutRestoreView = focusHost;
+ accessibilityFocusLayoutRestoreNode = viewRootImpl
+ .getAccessibilityFocusedVirtualView();
+ }
+
+ // If all else fails, maintain focus at the same
+ // position.
+ accessibilityFocusPosition = getPositionForView(focusChild);
+ }
+ }
}
- // Ensure the child containing focus, if any, has transient state.
- // If the list data hasn't changed, or if the adapter has stable
- // IDs, this will maintain focus.
+ View focusLayoutRestoreDirectChild = null;
+ View focusLayoutRestoreView = null;
+
+ // Take focus back to us temporarily to avoid the eventual call to
+ // clear focus when removing the focused child below from messing
+ // things up when ViewAncestor assigns focus back to someone else.
final View focusedChild = getFocusedChild();
if (focusedChild != null) {
- focusedChild.setHasTransientState(true);
+ // TODO: in some cases focusedChild.getParent() == null
+
+ // We can remember the focused view to restore after re-layout
+ // if the data hasn't changed, or if the focused position is a
+ // header or footer.
+ if (!dataChanged || isDirectChildHeaderOrFooter(focusedChild)) {
+ focusLayoutRestoreDirectChild = focusedChild;
+ // Remember the specific view that had focus.
+ focusLayoutRestoreView = findFocus();
+ if (focusLayoutRestoreView != null) {
+ // Tell it we are going to mess with it.
+ focusLayoutRestoreView.onStartTemporaryDetach();
+ }
+ }
+ requestFocus();
}
// Pull all children into the RecycleBin.
@@ -1656,20 +1694,24 @@
recycleBin.scrapActiveViews();
if (sel != null) {
- final boolean shouldPlaceFocus = mItemsCanFocus && hasFocus();
- final boolean maintainedFocus = focusedChild != null && focusedChild.hasFocus();
- if (shouldPlaceFocus && !maintainedFocus && !sel.hasFocus()) {
- if (sel.requestFocus()) {
- // Successfully placed focus, clear selection.
- sel.setSelected(false);
- mSelectorRect.setEmpty();
- } else {
- // Failed to place focus, clear current (invalid) focus.
+ // The current selected item should get focus if items are
+ // focusable.
+ if (mItemsCanFocus && hasFocus() && !sel.hasFocus()) {
+ final boolean focusWasTaken = (sel == focusLayoutRestoreDirectChild &&
+ focusLayoutRestoreView != null &&
+ focusLayoutRestoreView.requestFocus()) || sel.requestFocus();
+ if (!focusWasTaken) {
+ // Selected item didn't take focus, but we still want to
+ // make sure something else outside of the selected view
+ // has focus.
final View focused = getFocusedChild();
if (focused != null) {
focused.clearFocus();
}
positionSelector(INVALID_POSITION, sel);
+ } else {
+ sel.setSelected(false);
+ mSelectorRect.setEmpty();
}
} else {
positionSelector(INVALID_POSITION, sel);
@@ -1687,27 +1729,48 @@
mSelectedTop = 0;
mSelectorRect.setEmpty();
}
+
+ // Even if there is not selected position, we may need to
+ // restore focus (i.e. something focusable in touch mode).
+ if (hasFocus() && focusLayoutRestoreView != null) {
+ focusLayoutRestoreView.requestFocus();
+ }
}
- if (accessFocusedChild != null) {
- accessFocusedChild.setHasTransientState(false);
-
- // If we failed to maintain accessibility focus on the previous
- // view, attempt to restore it to the previous position.
- if (!accessFocusedChild.isAccessibilityFocused()
- && accessibilityFocusPosition != INVALID_POSITION) {
- // Bound the position within the visible children.
- final int position = MathUtils.constrain(
- accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1);
- final View restoreView = getChildAt(position);
- if (restoreView != null) {
- restoreView.requestAccessibilityFocus();
+ // Attempt to restore accessibility focus, if necessary.
+ if (viewRootImpl != null) {
+ final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost();
+ if (newAccessibilityFocusedView == null) {
+ if (accessibilityFocusLayoutRestoreView != null
+ && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) {
+ final AccessibilityNodeProvider provider =
+ accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
+ if (accessibilityFocusLayoutRestoreNode != null && provider != null) {
+ final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(
+ accessibilityFocusLayoutRestoreNode.getSourceNodeId());
+ provider.performAction(virtualViewId,
+ AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
+ } else {
+ accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
+ }
+ } else if (accessibilityFocusPosition != INVALID_POSITION) {
+ // Bound the position within the visible children.
+ final int position = MathUtils.constrain(
+ accessibilityFocusPosition - mFirstPosition, 0,
+ getChildCount() - 1);
+ final View restoreView = getChildAt(position);
+ if (restoreView != null) {
+ restoreView.requestAccessibilityFocus();
+ }
}
}
}
- if (focusedChild != null) {
- focusedChild.setHasTransientState(false);
+ // Tell focus view we are done mucking with it, if it is still in
+ // our view hierarchy.
+ if (focusLayoutRestoreView != null
+ && focusLayoutRestoreView.getWindowToken() != null) {
+ focusLayoutRestoreView.onFinishTemporaryDetach();
}
mLayoutMode = LAYOUT_NORMAL;
@@ -1734,6 +1797,30 @@
}
/**
+ * @param child a direct child of this list.
+ * @return Whether child is a header or footer view.
+ */
+ private boolean isDirectChildHeaderOrFooter(View child) {
+ final ArrayList<FixedViewInfo> headers = mHeaderViewInfos;
+ final int numHeaders = headers.size();
+ for (int i = 0; i < numHeaders; i++) {
+ if (child == headers.get(i).view) {
+ return true;
+ }
+ }
+
+ final ArrayList<FixedViewInfo> footers = mFooterViewInfos;
+ final int numFooters = footers.size();
+ for (int i = 0; i < numFooters; i++) {
+ if (child == footers.get(i).view) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Obtain the view and add it to our list of children. The view can be made
* fresh, converted from an unused view, or used as is if it was in the
* recycle bin.
@@ -1892,45 +1979,6 @@
}
/**
- * Sets the selected item and positions the selection y pixels from the top edge
- * of the ListView. (If in touch mode, the item will not be selected but it will
- * still be positioned appropriately.)
- *
- * @param position Index (starting at 0) of the data item to be selected.
- * @param y The distance from the top edge of the ListView (plus padding) that the
- * item will be positioned.
- */
- public void setSelectionFromTop(int position, int y) {
- if (mAdapter == null) {
- return;
- }
-
- if (!isInTouchMode()) {
- position = lookForSelectablePosition(position, true);
- if (position >= 0) {
- setNextSelectedPositionInt(position);
- }
- } else {
- mResurrectToPosition = position;
- }
-
- if (position >= 0) {
- mLayoutMode = LAYOUT_SPECIFIC;
- mSpecificTop = mListPadding.top + y;
-
- if (mNeedSync) {
- mSyncPosition = position;
- mSyncRowId = mAdapter.getItemId(position);
- }
-
- if (mPositionScroller != null) {
- mPositionScroller.stop();
- }
- requestLayout();
- }
- }
-
- /**
* Makes the item at the supplied position selected.
*
* @param position the position of the item to select
@@ -3746,6 +3794,79 @@
}
@Override
+ int getHeightForPosition(int position) {
+ final int height = super.getHeightForPosition(position);
+ if (shouldAdjustHeightForDivider(position)) {
+ return height + mDividerHeight;
+ }
+ return height;
+ }
+
+ private boolean shouldAdjustHeightForDivider(int itemIndex) {
+ final int dividerHeight = mDividerHeight;
+ final Drawable overscrollHeader = mOverScrollHeader;
+ final Drawable overscrollFooter = mOverScrollFooter;
+ final boolean drawOverscrollHeader = overscrollHeader != null;
+ final boolean drawOverscrollFooter = overscrollFooter != null;
+ final boolean drawDividers = dividerHeight > 0 && mDivider != null;
+
+ if (drawDividers) {
+ final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
+ final int itemCount = mItemCount;
+ final int headerCount = mHeaderViewInfos.size();
+ final int footerLimit = (itemCount - mFooterViewInfos.size());
+ final boolean isHeader = (itemIndex < headerCount);
+ final boolean isFooter = (itemIndex >= footerLimit);
+ final boolean headerDividers = mHeaderDividersEnabled;
+ final boolean footerDividers = mFooterDividersEnabled;
+ if ((headerDividers || !isHeader) && (footerDividers || !isFooter)) {
+ final ListAdapter adapter = mAdapter;
+ if (!mStackFromBottom) {
+ final boolean isLastItem = (itemIndex == (itemCount - 1));
+ if (!drawOverscrollFooter || !isLastItem) {
+ final int nextIndex = itemIndex + 1;
+ // Draw dividers between enabled items, headers
+ // and/or footers when enabled and requested, and
+ // after the last enabled item.
+ if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
+ && (nextIndex >= headerCount)) && (isLastItem
+ || adapter.isEnabled(nextIndex) && (footerDividers || !isFooter
+ && (nextIndex < footerLimit)))) {
+ return true;
+ } else if (fillForMissingDividers) {
+ return true;
+ }
+ }
+ } else {
+ final int start = drawOverscrollHeader ? 1 : 0;
+ final boolean isFirstItem = (itemIndex == start);
+ if (!isFirstItem) {
+ final int previousIndex = (itemIndex - 1);
+ // Draw dividers between enabled items, headers
+ // and/or footers when enabled and requested, and
+ // before the first enabled item.
+ if (adapter.isEnabled(itemIndex) && (headerDividers || !isHeader
+ && (previousIndex >= headerCount)) && (isFirstItem ||
+ adapter.isEnabled(previousIndex) && (footerDividers || !isFooter
+ && (previousIndex < footerLimit)))) {
+ return true;
+ } else if (fillForMissingDividers) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ AbsPositionScroller createPositionScroller() {
+ return new ListViewPositionScroller();
+ }
+
+ @Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(ListView.class.getName());
@@ -3757,7 +3878,8 @@
info.setClassName(ListView.class.getName());
final int count = getCount();
- final CollectionInfo collectionInfo = CollectionInfo.obtain(1, count, false);
+ final int selectionMode = getSelectionModeForAccessibility();
+ final CollectionInfo collectionInfo = CollectionInfo.obtain(1, count, false, selectionMode);
info.setCollectionInfo(collectionInfo);
}
@@ -3768,7 +3890,29 @@
final LayoutParams lp = (LayoutParams) view.getLayoutParams();
final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
- final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(0, 1, position, 1, isHeading);
+ final boolean isSelected = isItemChecked(position);
+ final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
+ 0, 1, position, 1, isHeading, isSelected);
info.setCollectionItemInfo(itemInfo);
}
+
+ /**
+ * Sub-position scroller that understands the layout of a ListView.
+ */
+ class ListViewPositionScroller extends AbsSubPositionScroller {
+ @Override
+ public int getRowForPosition(int position) {
+ return position;
+ }
+
+ @Override
+ public int getFirstPositionForRow(int row) {
+ return row;
+ }
+
+ @Override
+ public int getHeightForRow(int row) {
+ return getHeightForPosition(row);
+ }
+ }
}
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index bebe67f..90e80d3 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -748,14 +748,14 @@
// measurement is code for, "we got an unspecified mode in the
// RelativeLayout's measure spec."
if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
- if (childSize >= 0) {
- // The child specified an exact size.
- childSpecSize = childSize;
- childSpecMode = MeasureSpec.EXACTLY;
- } else if (childStart >= 0 && childEnd >= 0) {
+ if (childStart >= 0 && childEnd >= 0) {
// Constraints fixed both edges, so child has an exact size.
childSpecSize = Math.max(0, childEnd - childStart);
childSpecMode = MeasureSpec.EXACTLY;
+ } else if (childSize >= 0) {
+ // The child specified an exact size.
+ childSpecSize = childSize;
+ childSpecMode = MeasureSpec.EXACTLY;
} else {
// Allow the child to be whatever size it wants.
childSpecSize = 0;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index b204dfd..1cda631 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -731,10 +731,14 @@
}
}
- if (scheduleOtherSpellCheck) {
+ if (scheduleOtherSpellCheck && wordStart <= end) {
// Update range span: start new spell check from last wordStart
setRangeSpan(editable, wordStart, end);
} else {
+ if (DBG && scheduleOtherSpellCheck) {
+ Log.w(TAG, "Trying to schedule spellcheck for invalid region, from "
+ + wordStart + " to " + end);
+ }
removeRangeSpan(editable);
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 65b79fc..e5cb16f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5809,6 +5809,7 @@
int end = text.partialEndOffset;
if (end > N) end = N;
removeParcelableSpans(content, start, end);
+ // If start > end, content.replace will swap them before using them.
content.replace(start, end, text.text);
}
}
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index a7a7e7e..7640749 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -128,16 +128,20 @@
private Handler mHandler;
- View.OnClickListener mButtonHandler = new View.OnClickListener() {
+ private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
+ @Override
public void onClick(View v) {
- Message m = null;
+ final Message m;
if (v == mButtonPositive && mButtonPositiveMessage != null) {
m = Message.obtain(mButtonPositiveMessage);
} else if (v == mButtonNegative && mButtonNegativeMessage != null) {
m = Message.obtain(mButtonNegativeMessage);
} else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
m = Message.obtain(mButtonNeutralMessage);
+ } else {
+ m = null;
}
+
if (m != null) {
m.sendToTarget();
}
@@ -425,12 +429,13 @@
customView = null;
}
- if (customView == null || !canTextInput(customView)) {
+ final boolean hasCustomView = customView != null;
+ if (!hasCustomView || !canTextInput(customView)) {
mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
- if (customView != null) {
+ if (hasCustomView) {
final FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom);
custom.addView(customView, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
@@ -445,12 +450,11 @@
} else {
customPanel.setVisibility(View.GONE);
}
-
- /* Only display the divider if we have a title and a
- * custom view or a message.
- */
+
+ // Only display the divider if we have a title and a custom view or a
+ // message.
if (hasTitle) {
- View divider = null;
+ final View divider;
if (mMessage != null || customView != null || mListView != null) {
divider = mWindow.findViewById(R.id.titleDivider);
} else {
@@ -461,8 +465,9 @@
divider.setVisibility(View.VISIBLE);
}
}
-
- setBackground(topPanel, contentPanel, customPanel, hasButtons, a, hasTitle, buttonPanel);
+
+ setBackground(a, topPanel, contentPanel, customPanel, buttonPanel, hasTitle, hasCustomView,
+ hasButtons);
a.recycle();
}
@@ -620,76 +625,64 @@
}
}
- private void setBackground(LinearLayout topPanel, LinearLayout contentPanel,
- View customPanel, boolean hasButtons, TypedArray a, boolean hasTitle,
- View buttonPanel) {
-
- /* Get all the different background required */
- int fullDark = a.getResourceId(
- R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);
- int topDark = a.getResourceId(
- R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);
- int centerDark = a.getResourceId(
- R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);
- int bottomDark = a.getResourceId(
- R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);
- int fullBright = a.getResourceId(
- R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);
- int topBright = a.getResourceId(
+ private void setBackground(TypedArray a, View topPanel, View contentPanel, View customPanel,
+ View buttonPanel, boolean hasTitle, boolean hasCustomView, boolean hasButtons) {
+ final int topBright = a.getResourceId(
R.styleable.AlertDialog_topBright, R.drawable.popup_top_bright);
- int centerBright = a.getResourceId(
+ final int topDark = a.getResourceId(
+ R.styleable.AlertDialog_topDark, R.drawable.popup_top_dark);
+ final int centerBright = a.getResourceId(
R.styleable.AlertDialog_centerBright, R.drawable.popup_center_bright);
- int bottomBright = a.getResourceId(
- R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
- int bottomMedium = a.getResourceId(
- R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
-
- /*
- * We now set the background of all of the sections of the alert.
+ final int centerDark = a.getResourceId(
+ R.styleable.AlertDialog_centerDark, R.drawable.popup_center_dark);
+
+ /* We now set the background of all of the sections of the alert.
* First collect together each section that is being displayed along
* with whether it is on a light or dark background, then run through
* them setting their backgrounds. This is complicated because we need
* to correctly use the full, top, middle, and bottom graphics depending
* on how many views they are and where they appear.
*/
-
- View[] views = new View[4];
- boolean[] light = new boolean[4];
+
+ final View[] views = new View[4];
+ final boolean[] light = new boolean[4];
View lastView = null;
boolean lastLight = false;
-
+
int pos = 0;
if (hasTitle) {
views[pos] = topPanel;
light[pos] = false;
pos++;
}
-
+
/* The contentPanel displays either a custom text message or
* a ListView. If it's text we should use the dark background
* for ListView we should use the light background. If neither
* are there the contentPanel will be hidden so set it as null.
*/
- views[pos] = (contentPanel.getVisibility() == View.GONE)
- ? null : contentPanel;
+ views[pos] = contentPanel.getVisibility() == View.GONE ? null : contentPanel;
light[pos] = mListView != null;
pos++;
- if (customPanel != null) {
+
+ if (hasCustomView) {
views[pos] = customPanel;
light[pos] = mForceInverseBackground;
pos++;
}
+
if (hasButtons) {
views[pos] = buttonPanel;
light[pos] = true;
}
-
+
boolean setView = false;
- for (pos=0; pos<views.length; pos++) {
- View v = views[pos];
+ for (pos = 0; pos < views.length; pos++) {
+ final View v = views[pos];
if (v == null) {
continue;
}
+
if (lastView != null) {
if (!setView) {
lastView.setBackgroundResource(lastLight ? topBright : topDark);
@@ -698,23 +691,34 @@
}
setView = true;
}
+
lastView = v;
lastLight = light[pos];
}
-
+
if (lastView != null) {
if (setView) {
-
- /* ListViews will use the Bright background but buttons use
- * the Medium background.
- */
+ final int bottomBright = a.getResourceId(
+ R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
+ final int bottomMedium = a.getResourceId(
+ R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
+ final int bottomDark = a.getResourceId(
+ R.styleable.AlertDialog_bottomDark, R.drawable.popup_bottom_dark);
+
+ // ListViews will use the Bright background, but buttons use the
+ // Medium background.
lastView.setBackgroundResource(
lastLight ? (hasButtons ? bottomMedium : bottomBright) : bottomDark);
} else {
+ final int fullBright = a.getResourceId(
+ R.styleable.AlertDialog_fullBright, R.drawable.popup_full_bright);
+ final int fullDark = a.getResourceId(
+ R.styleable.AlertDialog_fullDark, R.drawable.popup_full_dark);
+
lastView.setBackgroundResource(lastLight ? fullBright : fullDark);
}
}
-
+
/* TODO: uncomment section below. The logic for this should be if
* it's a Contextual menu being displayed AND only a Cancel button
* is shown then do this.
@@ -739,12 +743,14 @@
mListView.addFooterView(buttonPanel);
*/
// }
-
- if ((mListView != null) && (mAdapter != null)) {
- mListView.setAdapter(mAdapter);
- if (mCheckedItem > -1) {
- mListView.setItemChecked(mCheckedItem, true);
- mListView.setSelection(mCheckedItem);
+
+ final ListView listView = mListView;
+ if (listView != null && mAdapter != null) {
+ listView.setAdapter(mAdapter);
+ final int checkedItem = mCheckedItem;
+ if (checkedItem > -1) {
+ listView.setItemChecked(checkedItem, true);
+ listView.setSelection(checkedItem);
}
}
}
@@ -969,7 +975,8 @@
if (mOnClickListener != null) {
listView.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView parent, View v, int position, long id) {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
mOnClickListener.onClick(dialog.mDialogInterface, position);
if (!mIsSingleChoice) {
dialog.mDialogInterface.dismiss();
@@ -978,7 +985,8 @@
});
} else if (mOnCheckboxClickListener != null) {
listView.setOnItemClickListener(new OnItemClickListener() {
- public void onItemClick(AdapterView parent, View v, int position, long id) {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
if (mCheckedItems != null) {
mCheckedItems[position] = listView.isItemChecked(position);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 70f90d3..1eda373 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -27,8 +27,9 @@
Intent intent = getIntent();
Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
if (!(targetParcelable instanceof Intent)) {
- Log.w("ChooseActivity", "Target is not an intent: " + targetParcelable);
+ Log.w("ChooserActivity", "Target is not an intent: " + targetParcelable);
finish();
+ super.onCreate(null);
return;
}
Intent target = (Intent)targetParcelable;
@@ -42,9 +43,10 @@
initialIntents = new Intent[pa.length];
for (int i=0; i<pa.length; i++) {
if (!(pa[i] instanceof Intent)) {
- Log.w("ChooseActivity", "Initial intent #" + i
+ Log.w("ChooserActivity", "Initial intent #" + i
+ " not an Intent: " + pa[i]);
finish();
+ super.onCreate(null);
return;
}
initialIntents[i] = (Intent)pa[i];
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 9a04760..1155cbb 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -51,6 +51,7 @@
void noteScreenOff();
void noteInputEvent();
void noteUserActivity(int uid, int event);
+ void noteDataConnectionActive(String label, boolean active);
void notePhoneOn();
void notePhoneOff();
void notePhoneSignalStrength(in SignalStrength signalStrength);
@@ -61,8 +62,10 @@
void noteWifiRunning(in WorkSource ws);
void noteWifiRunningChanged(in WorkSource oldWs, in WorkSource newWs);
void noteWifiStopped(in WorkSource ws);
+ void noteWifiState(int wifiState, String accessPoint);
void noteBluetoothOn();
void noteBluetoothOff();
+ void noteBluetoothState(int bluetoothState);
void noteFullWifiLockAcquired(int uid);
void noteFullWifiLockReleased(int uid);
void noteWifiScanStarted(int uid);
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 4dd4a45..b1535e3 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1018,7 +1018,7 @@
for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
final ProcessState ps = pkgState.mProcesses.valueAt(iproc);
if (ps.isInUse()) {
- pkgState.mProcesses.valueAt(iproc).resetSafely(now);
+ ps.resetSafely(now);
ps.mCommonProcess.mTmpNumInUse++;
ps.mCommonProcess.mTmpFoundSubProc = ps;
} else {
@@ -1029,7 +1029,7 @@
for (int isvc=pkgState.mServices.size()-1; isvc>=0; isvc--) {
final ServiceState ss = pkgState.mServices.valueAt(isvc);
if (ss.isInUse()) {
- pkgState.mServices.valueAt(isvc).resetSafely(now);
+ ss.resetSafely(now);
} else {
pkgState.mServices.removeAt(isvc);
}
@@ -3142,7 +3142,7 @@
}
public boolean isInUse() {
- return mOwner != null;
+ return mOwner != null || mRestarting;
}
void add(ServiceState other) {
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index a3323e9..2fe2494 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -35,6 +35,11 @@
import java.io.FileOutputStream;
import java.io.IOException;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+import libcore.io.StructStat;
+import static libcore.io.OsConstants.*;
+
/**
* Backup transport for stashing stuff into a known location on disk, and
* later restoring from there. For testing only.
@@ -96,7 +101,16 @@
}
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
- if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
+ if (DEBUG) {
+ try {
+ StructStat ss = Libcore.os.fstat(data.getFileDescriptor());
+ Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName
+ + " size=" + ss.st_size);
+ } catch (ErrnoException e) {
+ Log.w(TAG, "Unable to stat input file in performBackup() on "
+ + packageInfo.packageName);
+ }
+ }
File packageDir = new File(mDataDir, packageInfo.packageName);
packageDir.mkdirs();
@@ -130,7 +144,16 @@
buf = new byte[bufSize];
}
changeSet.readEntityData(buf, 0, dataSize);
- if (DEBUG) Log.v(TAG, " data size " + dataSize);
+ if (DEBUG) {
+ try {
+ long cur = Libcore.os.lseek(data.getFileDescriptor(), 0, SEEK_CUR);
+ Log.v(TAG, " read entity data; new pos=" + cur);
+ }
+ catch (ErrnoException e) {
+ Log.w(TAG, "Unable to stat input file in performBackup() on "
+ + packageInfo.packageName);
+ }
+ }
try {
entity.write(buf, 0, dataSize);
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 8282d23..e2a2b1e 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -17,6 +17,7 @@
package com.android.internal.net;
import static android.net.NetworkStats.SET_ALL;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
@@ -26,6 +27,7 @@
import android.os.SystemClock;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
import java.io.File;
@@ -165,22 +167,32 @@
}
public NetworkStats readNetworkStatsDetail() throws IOException {
- return readNetworkStatsDetail(UID_ALL);
+ return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
}
- public NetworkStats readNetworkStatsDetail(int limitUid) throws IOException {
+ public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag,
+ NetworkStats lastStats)
+ throws IOException {
if (USE_NATIVE_PARSING) {
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
- if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid) != 0) {
+ final NetworkStats stats;
+ if (lastStats != null) {
+ stats = lastStats;
+ stats.setElapsedRealtime(SystemClock.elapsedRealtime());
+ } else {
+ stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
+ }
+ if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
+ limitIfaces, limitTag) != 0) {
throw new IOException("Failed to parse network stats");
}
if (SANITY_CHECK_NATIVE) {
- final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
+ final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid,
+ limitIfaces, limitTag);
assertEquals(javaStats, stats);
}
return stats;
} else {
- return javaReadNetworkStatsDetail(mStatsXtUid, limitUid);
+ return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag);
}
}
@@ -189,7 +201,8 @@
* expected to monotonically increase since device boot.
*/
@VisibleForTesting
- public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid)
+ public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid,
+ String[] limitIfaces, int limitTag)
throws IOException {
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
@@ -222,7 +235,9 @@
entry.txBytes = reader.nextLong();
entry.txPackets = reader.nextLong();
- if (limitUid == UID_ALL || limitUid == entry.uid) {
+ if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface))
+ && (limitUid == UID_ALL || limitUid == entry.uid)
+ && (limitTag == TAG_ALL || limitTag == entry.tag)) {
stats.addValues(entry);
}
@@ -264,5 +279,5 @@
*/
@VisibleForTesting
public static native int nativeReadNetworkStatsDetail(
- NetworkStats stats, String path, int limitUid);
+ NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag);
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index c22a5e9..e0cf435 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -640,9 +640,10 @@
final long mobileTx = mStats.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
final long mobileData = mobileRx + mobileTx;
- final long radioDataUptimeMs = mStats.getRadioDataUptime() / 1000;
- final double mobilePps = radioDataUptimeMs != 0
- ? mobileData / (double)radioDataUptimeMs
+ final long radioDataUptimeMs
+ = mStats.getMobileRadioActiveTime(mBatteryRealtime, mStatsType) / 1000;
+ final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
+ ? (mobileData / (double)radioDataUptimeMs)
: (((double)MOBILE_BPS) / 8 / 2048);
return (MOBILE_POWER / mobilePps) / (60*60);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 82dcbdb..40e8727 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
+import static android.net.NetworkStats.UID_ALL;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.bluetooth.BluetoothDevice;
@@ -23,6 +24,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
+import android.os.BadParcelableException;
import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.FileUtils;
@@ -51,20 +53,17 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.JournaledFile;
-import com.google.android.collect.Sets;
-import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
-import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -88,7 +87,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 79 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 85 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -273,9 +272,18 @@
boolean mGlobalWifiRunning;
StopwatchTimer mGlobalWifiRunningTimer;
+ int mWifiState = -1;
+ final StopwatchTimer[] mWifiStateTimer = new StopwatchTimer[NUM_WIFI_STATES];
+
boolean mBluetoothOn;
StopwatchTimer mBluetoothOnTimer;
+ int mBluetoothState = -1;
+ final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
+
+ boolean mMobileRadioActive;
+ StopwatchTimer mMobileRadioActiveTimer;
+
/** Bluetooth headset object */
BluetoothHeadset mBtHeadset;
@@ -310,9 +318,6 @@
long mLastWriteTime = 0; // Milliseconds
- private long mRadioDataUptime;
- private long mRadioDataStart;
-
private int mBluetoothPingCount;
private int mBluetoothPingStart = -1;
@@ -365,12 +370,17 @@
new HashMap<String, KernelWakelockStats>();
private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
- private NetworkStats mLastSnapshot;
+ private NetworkStats mCurMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
+ private NetworkStats mLastMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
+ private NetworkStats mCurWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
+ private NetworkStats mLastWifiSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
+ private NetworkStats mTmpNetworkStats;
+ private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
@GuardedBy("this")
- private HashSet<String> mMobileIfaces = Sets.newHashSet();
+ private String[] mMobileIfaces = new String[0];
@GuardedBy("this")
- private HashSet<String> mWifiIfaces = Sets.newHashSet();
+ private String[] mWifiIfaces = new String[0];
// For debugging
public BatteryStatsImpl() {
@@ -1164,10 +1174,9 @@
+ " mAcquireTime=" + mAcquireTime);
}
- void startRunningLocked(BatteryStatsImpl stats) {
+ void startRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
if (mNesting++ == 0) {
- mUpdateTime = stats.getBatteryRealtimeLocked(
- SystemClock.elapsedRealtime() * 1000);
+ mUpdateTime = stats.getBatteryRealtimeLocked(elapsedRealtime * 1000);
if (mTimerPool != null) {
// Accumulate time to all currently active timers before adding
// this new one to the pool.
@@ -1190,7 +1199,7 @@
return mNesting > 0;
}
- void stopRunningLocked(BatteryStatsImpl stats) {
+ void stopRunningLocked(BatteryStatsImpl stats, long elapsedRealtime) {
// Ignore attempt to stop a timer that isn't running
if (mNesting == 0) {
return;
@@ -1203,8 +1212,8 @@
// Remove this timer from the active pool
mTimerPool.remove(this);
} else {
- final long realtime = SystemClock.elapsedRealtime() * 1000;
- final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime);
+ final long batteryRealtime = stats.getBatteryRealtimeLocked(
+ elapsedRealtime * 1000);
mNesting = 1;
mTotalTime = computeRunTimeLocked(batteryRealtime);
mNesting = 0;
@@ -1432,44 +1441,6 @@
return kwlt;
}
- /**
- * Radio uptime in microseconds when transferring data. This value is very approximate.
- * @return
- */
- private long getCurrentRadioDataUptime() {
- try {
- File awakeTimeFile = new File("/sys/devices/virtual/net/rmnet0/awake_time_ms");
- if (!awakeTimeFile.exists()) return 0;
- BufferedReader br = new BufferedReader(new FileReader(awakeTimeFile));
- String line = br.readLine();
- br.close();
- return Long.parseLong(line) * 1000;
- } catch (NumberFormatException nfe) {
- // Nothing
- } catch (IOException ioe) {
- // Nothing
- }
- return 0;
- }
-
- /**
- * @deprecated use getRadioDataUptime
- */
- public long getRadioDataUptimeMs() {
- return getRadioDataUptime() / 1000;
- }
-
- /**
- * Returns the duration that the cell radio was up for data transfers.
- */
- public long getRadioDataUptime() {
- if (mRadioDataStart == -1) {
- return mRadioDataUptime;
- } else {
- return getCurrentRadioDataUptime() - mRadioDataStart;
- }
- }
-
private int getCurrentBluetoothPingCount() {
if (mBtHeadset != null) {
List<BluetoothDevice> deviceList = mBtHeadset.getConnectedDevices();
@@ -1520,14 +1491,16 @@
}
// Part of initial delta int that specifies the time delta.
- static final int DELTA_TIME_MASK = 0xfffff;
- static final int DELTA_TIME_LONG = 0xfffff; // The delta is a following long
- static final int DELTA_TIME_INT = 0xffffe; // The delta is a following int
- static final int DELTA_TIME_ABS = 0xffffd; // Following is an entire abs update.
+ static final int DELTA_TIME_MASK = 0x7ffff;
+ static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long
+ static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int
+ static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update.
// Flag in delta int: a new battery level int follows.
- static final int DELTA_BATTERY_LEVEL_FLAG = 0x00100000;
+ static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
// Flag in delta int: a new full state and battery status int follows.
- static final int DELTA_STATE_FLAG = 0x00200000;
+ static final int DELTA_STATE_FLAG = 0x00100000;
+ // Flag in delta int: a new full state2 int follows.
+ static final int DELTA_STATE2_FLAG = 0x00200000;
// Flag in delta int: contains a wakelock tag.
static final int DELTA_WAKELOCK_FLAG = 0x00400000;
// Flag in delta int: contains an event description.
@@ -1963,10 +1936,6 @@
mUnpluggables.get(i).unplug(elapsedRealtime, batteryUptime, batteryRealtime);
}
- // Track radio awake time
- mRadioDataStart = getCurrentRadioDataUptime();
- mRadioDataUptime = 0;
-
// Track bt headset ping count
mBluetoothPingStart = getCurrentBluetoothPingCount();
mBluetoothPingCount = 0;
@@ -1977,10 +1946,6 @@
mUnpluggables.get(i).plug(elapsedRealtime, batteryUptime, batteryRealtime);
}
- // Track radio awake time
- mRadioDataUptime = getRadioDataUptime();
- mRadioDataStart = -1;
-
// Track bt headset ping count
mBluetoothPingCount = getBluetoothPingCount();
mBluetoothPingStart = -1;
@@ -2049,6 +2014,7 @@
public void noteStartWakeLocked(int uid, int pid, String name, int type,
boolean unimportantForLogging) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (type == WAKE_TYPE_PARTIAL) {
// Only care about partial wake locks, since full wake locks
// will be canceled when the user puts the screen to sleep.
@@ -2060,7 +2026,7 @@
mHistoryCur.wakelockTag.string = name;
mHistoryCur.wakelockTag.uid = uid;
mWakeLockImportant = !unimportantForLogging;
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
} else if (!mWakeLockImportant && !unimportantForLogging) {
if (mHistoryLastWritten.wakelockTag != null) {
// We'll try to update the last tag.
@@ -2068,7 +2034,7 @@
mHistoryCur.wakelockTag = mHistoryCur.localWakelockTag;
mHistoryCur.wakelockTag.string = name;
mHistoryCur.wakelockTag.uid = uid;
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
mWakeLockImportant = true;
}
@@ -2079,19 +2045,20 @@
Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
}
- getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type);
+ getUidStatsLocked(uid).noteStartWakeLocked(pid, name, type, elapsedRealtime);
}
}
public void noteStopWakeLocked(int uid, int pid, String name, int type) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (type == WAKE_TYPE_PARTIAL) {
mWakeLockNesting--;
if (mWakeLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WAKE_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop wake lock to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
}
if (uid >= 0) {
@@ -2099,7 +2066,7 @@
Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
mHandler.sendMessageDelayed(m, DELAY_UPDATE_WAKELOCKS);
}
- getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type);
+ getUidStatsLocked(uid).noteStopWakeLocked(pid, name, type, elapsedRealtime);
}
}
@@ -2256,64 +2223,70 @@
public void noteStartSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mSensorNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start sensor to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
mSensorNesting++;
- getUidStatsLocked(uid).noteStartSensor(sensor);
+ getUidStatsLocked(uid).noteStartSensor(sensor, elapsedRealtime);
}
public void noteStopSensorLocked(int uid, int sensor) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mSensorNesting--;
if (mSensorNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_SENSOR_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop sensor to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
- getUidStatsLocked(uid).noteStopSensor(sensor);
+ getUidStatsLocked(uid).noteStopSensor(sensor, elapsedRealtime);
}
int mGpsNesting;
public void noteStartGpsLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mGpsNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Start GPS to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
mGpsNesting++;
- getUidStatsLocked(uid).noteStartGps();
+ getUidStatsLocked(uid).noteStartGps(elapsedRealtime);
}
public void noteStopGpsLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mGpsNesting--;
if (mGpsNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_GPS_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Stop GPS to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
- getUidStatsLocked(uid).noteStopGps();
+ getUidStatsLocked(uid).noteStopGps(elapsedRealtime);
}
public void noteScreenOnLocked() {
if (!mScreenOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states |= HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mScreenOn = true;
- mScreenOnTimer.startRunningLocked(this);
+ mScreenOnTimer.startRunningLocked(this, elapsedRealtime);
if (mScreenBrightnessBin >= 0) {
- mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this);
+ mScreenBrightnessTimer[mScreenBrightnessBin].startRunningLocked(this,
+ elapsedRealtime);
}
// Fake a wake lock, so we consider the device waked as long
@@ -2329,14 +2302,16 @@
public void noteScreenOffLocked() {
if (mScreenOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states &= ~HistoryItem.STATE_SCREEN_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Screen off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mScreenOn = false;
- mScreenOnTimer.stopRunningLocked(this);
+ mScreenOnTimer.stopRunningLocked(this, elapsedRealtime);
if (mScreenBrightnessBin >= 0) {
- mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+ mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this,
+ elapsedRealtime);
}
noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
@@ -2354,16 +2329,18 @@
if (bin < 0) bin = 0;
else if (bin >= NUM_SCREEN_BRIGHTNESS_BINS) bin = NUM_SCREEN_BRIGHTNESS_BINS-1;
if (mScreenBrightnessBin != bin) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_BRIGHTNESS_MASK)
| (bin << HistoryItem.STATE_BRIGHTNESS_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Screen brightness " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
if (mScreenOn) {
if (mScreenBrightnessBin >= 0) {
- mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this);
+ mScreenBrightnessTimer[mScreenBrightnessBin].stopRunningLocked(this,
+ elapsedRealtime);
}
- mScreenBrightnessTimer[bin].startRunningLocked(this);
+ mScreenBrightnessTimer[bin].startRunningLocked(this, elapsedRealtime);
}
mScreenBrightnessBin = bin;
}
@@ -2378,35 +2355,60 @@
getUidStatsLocked(uid).noteUserActivityLocked(event);
}
+ public void noteDataConnectionActive(String label, boolean active) {
+ try {
+ int type = Integer.parseInt(label);
+ if (ConnectivityManager.isNetworkTypeMobile(type)) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ if (mMobileRadioActive != active) {
+ if (active) mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ else mHistoryCur.states &= ~HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
+ if (DEBUG_HISTORY) Slog.v(TAG, "Mobile network active " + active + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime);
+ mMobileRadioActive = active;
+ if (active) mMobileRadioActiveTimer.startRunningLocked(this, elapsedRealtime);
+ else mMobileRadioActiveTimer.stopRunningLocked(this, elapsedRealtime);
+ }
+ }
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Bad data connection label: " + label, e);
+ return;
+ }
+ }
+
public void notePhoneOnLocked() {
if (!mPhoneOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mPhoneOn = true;
- mPhoneOnTimer.startRunningLocked(this);
+ mPhoneOnTimer.startRunningLocked(this, elapsedRealtime);
}
}
public void notePhoneOffLocked() {
if (mPhoneOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mPhoneOn = false;
- mPhoneOnTimer.stopRunningLocked(this);
+ mPhoneOnTimer.stopRunningLocked(this, elapsedRealtime);
}
}
void stopAllSignalStrengthTimersLocked(int except) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
for (int i = 0; i < SignalStrength.NUM_SIGNAL_STRENGTH_BINS; i++) {
if (i == except) {
continue;
}
while (mPhoneSignalStrengthsTimer[i].isRunningLocked()) {
- mPhoneSignalStrengthsTimer[i].stopRunningLocked(this);
+ mPhoneSignalStrengthsTimer[i].stopRunningLocked(this, elapsedRealtime);
}
}
}
@@ -2424,26 +2426,28 @@
return state;
}
- private void updateAllPhoneStateLocked(int state, int simState, int bin) {
+ private void updateAllPhoneStateLocked(int state, int simState, int strengthBin) {
boolean scanning = false;
boolean newHistory = false;
mPhoneServiceStateRaw = state;
mPhoneSimStateRaw = simState;
- mPhoneSignalStrengthBinRaw = bin;
+ mPhoneSignalStrengthBinRaw = strengthBin;
+
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (simState == TelephonyManager.SIM_STATE_ABSENT) {
// In this case we will always be STATE_OUT_OF_SERVICE, so need
// to infer that we are scanning from other data.
if (state == ServiceState.STATE_OUT_OF_SERVICE
- && bin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+ && strengthBin > SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
state = ServiceState.STATE_IN_SERVICE;
}
}
// If the phone is powered off, stop all timers.
if (state == ServiceState.STATE_POWER_OFF) {
- bin = -1;
+ strengthBin = -1;
// If we are in service, make sure the correct signal string timer is running.
} else if (state == ServiceState.STATE_IN_SERVICE) {
@@ -2453,13 +2457,13 @@
// bin and have the scanning bit set.
} else if (state == ServiceState.STATE_OUT_OF_SERVICE) {
scanning = true;
- bin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ strengthBin = SignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
if (!mPhoneSignalScanningTimer.isRunningLocked()) {
mHistoryCur.states |= HistoryItem.STATE_PHONE_SCANNING_FLAG;
newHistory = true;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
+ Integer.toHexString(mHistoryCur.states));
- mPhoneSignalScanningTimer.startRunningLocked(this);
+ mPhoneSignalScanningTimer.startRunningLocked(this, elapsedRealtime);
}
}
@@ -2470,7 +2474,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Phone stopped scanning to: "
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
- mPhoneSignalScanningTimer.stopRunningLocked(this);
+ mPhoneSignalScanningTimer.stopRunningLocked(this, elapsedRealtime);
}
}
@@ -2483,27 +2487,29 @@
mPhoneServiceState = state;
}
- if (mPhoneSignalStrengthBin != bin) {
+ if (mPhoneSignalStrengthBin != strengthBin) {
if (mPhoneSignalStrengthBin >= 0) {
- mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this);
+ mPhoneSignalStrengthsTimer[mPhoneSignalStrengthBin].stopRunningLocked(this,
+ elapsedRealtime);
}
- if (bin >= 0) {
- if (!mPhoneSignalStrengthsTimer[bin].isRunningLocked()) {
- mPhoneSignalStrengthsTimer[bin].startRunningLocked(this);
+ if (strengthBin >= 0) {
+ if (!mPhoneSignalStrengthsTimer[strengthBin].isRunningLocked()) {
+ mPhoneSignalStrengthsTimer[strengthBin].startRunningLocked(this,
+ elapsedRealtime);
}
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_SIGNAL_STRENGTH_MASK)
- | (bin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
- if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + bin + " to: "
+ | (strengthBin << HistoryItem.STATE_SIGNAL_STRENGTH_SHIFT);
+ if (DEBUG_HISTORY) Slog.v(TAG, "Signal strength " + strengthBin + " to: "
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
} else {
stopAllSignalStrengthTimersLocked(-1);
}
- mPhoneSignalStrengthBin = bin;
+ mPhoneSignalStrengthBin = strengthBin;
}
if (newHistory) {
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
}
@@ -2577,105 +2583,113 @@
}
if (DEBUG) Log.i(TAG, "Phone Data Connection -> " + dataType + " = " + hasData);
if (mPhoneDataConnectionType != bin) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states = (mHistoryCur.states&~HistoryItem.STATE_DATA_CONNECTION_MASK)
| (bin << HistoryItem.STATE_DATA_CONNECTION_SHIFT);
if (DEBUG_HISTORY) Slog.v(TAG, "Data connection " + bin + " to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
if (mPhoneDataConnectionType >= 0) {
- mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this);
+ mPhoneDataConnectionsTimer[mPhoneDataConnectionType].stopRunningLocked(this,
+ elapsedRealtime);
}
mPhoneDataConnectionType = bin;
- mPhoneDataConnectionsTimer[bin].startRunningLocked(this);
+ mPhoneDataConnectionsTimer[bin].startRunningLocked(this, elapsedRealtime);
}
}
public void noteWifiOnLocked() {
if (!mWifiOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states |= HistoryItem.STATE_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mWifiOn = true;
- mWifiOnTimer.startRunningLocked(this);
+ mWifiOnTimer.startRunningLocked(this, elapsedRealtime);
}
}
public void noteWifiOffLocked() {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mWifiOn) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mWifiOn = false;
- mWifiOnTimer.stopRunningLocked(this);
+ mWifiOnTimer.stopRunningLocked(this, elapsedRealtime);
}
if (mWifiOnUid >= 0) {
- getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked();
+ getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked(elapsedRealtime);
mWifiOnUid = -1;
}
}
public void noteAudioOnLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (!mAudioOn) {
mHistoryCur.states |= HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mAudioOn = true;
- mAudioOnTimer.startRunningLocked(this);
+ mAudioOnTimer.startRunningLocked(this, elapsedRealtime);
}
- getUidStatsLocked(uid).noteAudioTurnedOnLocked();
+ getUidStatsLocked(uid).noteAudioTurnedOnLocked(elapsedRealtime);
}
public void noteAudioOffLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mAudioOn) {
mHistoryCur.states &= ~HistoryItem.STATE_AUDIO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Audio off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mAudioOn = false;
- mAudioOnTimer.stopRunningLocked(this);
+ mAudioOnTimer.stopRunningLocked(this, elapsedRealtime);
}
- getUidStatsLocked(uid).noteAudioTurnedOffLocked();
+ getUidStatsLocked(uid).noteAudioTurnedOffLocked(elapsedRealtime);
}
public void noteVideoOnLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (!mVideoOn) {
mHistoryCur.states |= HistoryItem.STATE_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mVideoOn = true;
- mVideoOnTimer.startRunningLocked(this);
+ mVideoOnTimer.startRunningLocked(this, elapsedRealtime);
}
- getUidStatsLocked(uid).noteVideoTurnedOnLocked();
+ getUidStatsLocked(uid).noteVideoTurnedOnLocked(elapsedRealtime);
}
public void noteVideoOffLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mVideoOn) {
mHistoryCur.states &= ~HistoryItem.STATE_VIDEO_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Video off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mVideoOn = false;
- mVideoOnTimer.stopRunningLocked(this);
+ mVideoOnTimer.stopRunningLocked(this, elapsedRealtime);
}
- getUidStatsLocked(uid).noteVideoTurnedOffLocked();
+ getUidStatsLocked(uid).noteVideoTurnedOffLocked(elapsedRealtime);
}
public void noteActivityResumedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteActivityResumedLocked();
+ getUidStatsLocked(uid).noteActivityResumedLocked(SystemClock.elapsedRealtime());
}
public void noteActivityPausedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteActivityPausedLocked();
+ getUidStatsLocked(uid).noteActivityPausedLocked(SystemClock.elapsedRealtime());
}
public void noteVibratorOnLocked(int uid, long durationMillis) {
@@ -2690,16 +2704,17 @@
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states |= HistoryItem.STATE_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI running to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(SystemClock.elapsedRealtime());
mGlobalWifiRunning = true;
- mGlobalWifiRunningTimer.startRunningLocked(this);
+ mGlobalWifiRunningTimer.startRunningLocked(this, elapsedRealtime);
int N = ws.size();
for (int i=0; i<N; i++) {
int uid = mapUid(ws.get(i));
- getUidStatsLocked(uid).noteWifiRunningLocked();
+ getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
@@ -2708,15 +2723,16 @@
public void noteWifiRunningChangedLocked(WorkSource oldWs, WorkSource newWs) {
if (mGlobalWifiRunning) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
int N = oldWs.size();
for (int i=0; i<N; i++) {
int uid = mapUid(oldWs.get(i));
- getUidStatsLocked(uid).noteWifiStoppedLocked();
+ getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
N = newWs.size();
for (int i=0; i<N; i++) {
int uid = mapUid(newWs.get(i));
- getUidStatsLocked(uid).noteWifiRunningLocked();
+ getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
} else {
Log.w(TAG, "noteWifiRunningChangedLocked -- called while WIFI not running");
@@ -2725,41 +2741,69 @@
public void noteWifiStoppedLocked(WorkSource ws) {
if (mGlobalWifiRunning) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RUNNING_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI stopped to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mGlobalWifiRunning = false;
- mGlobalWifiRunningTimer.stopRunningLocked(this);
+ mGlobalWifiRunningTimer.stopRunningLocked(this, elapsedRealtime);
int N = ws.size();
for (int i=0; i<N; i++) {
int uid = mapUid(ws.get(i));
- getUidStatsLocked(uid).noteWifiStoppedLocked();
+ getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
}
+ public void noteWifiStateLocked(int wifiState, String accessPoint) {
+ if (DEBUG) Log.i(TAG, "WiFi state -> " + wifiState);
+ if (mWifiState != wifiState) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ if (mWifiState >= 0) {
+ mWifiStateTimer[mWifiState].stopRunningLocked(this, elapsedRealtime);
+ }
+ mWifiState = wifiState;
+ mWifiStateTimer[wifiState].startRunningLocked(this, elapsedRealtime);
+ }
+ }
+
public void noteBluetoothOnLocked() {
if (!mBluetoothOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mBluetoothOn = true;
- mBluetoothOnTimer.startRunningLocked(this);
+ mBluetoothOnTimer.startRunningLocked(this, elapsedRealtime);
}
}
public void noteBluetoothOffLocked() {
if (mBluetoothOn) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
mBluetoothOn = false;
- mBluetoothOnTimer.stopRunningLocked(this);
+ mBluetoothOnTimer.stopRunningLocked(this, elapsedRealtime);
+ }
+ }
+
+ public void noteBluetoothStateLocked(int bluetoothState) {
+ if (DEBUG) Log.i(TAG, "Bluetooth state -> " + bluetoothState);
+ if (mBluetoothState != bluetoothState) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ if (mBluetoothState >= 0) {
+ mBluetoothStateTimer[mBluetoothState].stopRunningLocked(this,
+ elapsedRealtime);
+ }
+ mBluetoothState = bluetoothState;
+ mBluetoothStateTimer[bluetoothState].startRunningLocked(this, elapsedRealtime);
}
}
@@ -2767,88 +2811,96 @@
public void noteFullWifiLockAcquiredLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mWifiFullLockNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
mWifiFullLockNesting++;
- getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked();
+ getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
}
public void noteFullWifiLockReleasedLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mWifiFullLockNesting--;
if (mWifiFullLockNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_FULL_LOCK_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
- getUidStatsLocked(uid).noteFullWifiLockReleasedLocked();
+ getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
}
int mWifiScanNesting = 0;
public void noteWifiScanStartedLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mWifiScanNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan started for: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
mWifiScanNesting++;
- getUidStatsLocked(uid).noteWifiScanStartedLocked();
+ getUidStatsLocked(uid).noteWifiScanStartedLocked(elapsedRealtime);
}
public void noteWifiScanStoppedLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mWifiScanNesting--;
if (mWifiScanNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_SCAN_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI scan stopped for: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
- getUidStatsLocked(uid).noteWifiScanStoppedLocked();
+ getUidStatsLocked(uid).noteWifiScanStoppedLocked(elapsedRealtime);
}
public void noteWifiBatchedScanStartedLocked(int uid, int csph) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ getUidStatsLocked(uid).noteWifiBatchedScanStartedLocked(csph, elapsedRealtime);
}
public void noteWifiBatchedScanStoppedLocked(int uid) {
uid = mapUid(uid);
- getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked();
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ getUidStatsLocked(uid).noteWifiBatchedScanStoppedLocked(elapsedRealtime);
}
int mWifiMulticastNesting = 0;
public void noteWifiMulticastEnabledLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
if (mWifiMulticastNesting == 0) {
mHistoryCur.states |= HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
mWifiMulticastNesting++;
- getUidStatsLocked(uid).noteWifiMulticastEnabledLocked();
+ getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
}
public void noteWifiMulticastDisabledLocked(int uid) {
uid = mapUid(uid);
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
mWifiMulticastNesting--;
if (mWifiMulticastNesting == 0) {
mHistoryCur.states &= ~HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
+ Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(SystemClock.elapsedRealtime());
+ addHistoryRecordLocked(elapsedRealtime);
}
- getUidStatsLocked(uid).noteWifiMulticastDisabledLocked();
+ getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
}
public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) {
@@ -2907,16 +2959,45 @@
}
}
+ private static String[] includeInStringArray(String[] array, String str) {
+ if (ArrayUtils.indexOf(array, str) >= 0) {
+ return array;
+ }
+ String[] newArray = new String[array.length+1];
+ System.arraycopy(array, 0, newArray, 0, array.length);
+ newArray[array.length] = str;
+ return newArray;
+ }
+
+ private static String[] excludeFromStringArray(String[] array, String str) {
+ int index = ArrayUtils.indexOf(array, str);
+ if (index >= 0) {
+ String[] newArray = new String[array.length-1];
+ if (index > 0) {
+ System.arraycopy(array, 0, newArray, 0, index);
+ }
+ if (index < array.length-1) {
+ System.arraycopy(array, index+1, newArray, index, array.length-index-1);
+ }
+ return newArray;
+ }
+ return array;
+ }
+
public void noteNetworkInterfaceTypeLocked(String iface, int networkType) {
if (ConnectivityManager.isNetworkTypeMobile(networkType)) {
- mMobileIfaces.add(iface);
+ mMobileIfaces = includeInStringArray(mMobileIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note mobile iface " + iface + ": " + mMobileIfaces);
} else {
- mMobileIfaces.remove(iface);
+ mMobileIfaces = excludeFromStringArray(mMobileIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note non-mobile iface " + iface + ": " + mMobileIfaces);
}
if (ConnectivityManager.isNetworkTypeWifi(networkType)) {
- mWifiIfaces.add(iface);
+ mWifiIfaces = includeInStringArray(mWifiIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note wifi iface " + iface + ": " + mWifiIfaces);
} else {
- mWifiIfaces.remove(iface);
+ mWifiIfaces = excludeFromStringArray(mWifiIfaces, iface);
+ if (DEBUG) Slog.d(TAG, "Note non-wifi iface " + iface + ": " + mWifiIfaces);
}
}
@@ -2971,6 +3052,10 @@
return mPhoneDataConnectionsTimer[dataType].getCountLocked(which);
}
+ @Override public long getMobileRadioActiveTime(long batteryRealtime, int which) {
+ return mMobileRadioActiveTimer.getTotalTimeLocked(batteryRealtime, which);
+ }
+
@Override public long getWifiOnTime(long batteryRealtime, int which) {
return mWifiOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
@@ -2979,10 +3064,30 @@
return mGlobalWifiRunningTimer.getTotalTimeLocked(batteryRealtime, which);
}
+ @Override public long getWifiStateTime(int wifiState,
+ long batteryRealtime, int which) {
+ return mWifiStateTimer[wifiState].getTotalTimeLocked(
+ batteryRealtime, which);
+ }
+
+ @Override public int getWifiStateCount(int wifiState, int which) {
+ return mWifiStateTimer[wifiState].getCountLocked(which);
+ }
+
@Override public long getBluetoothOnTime(long batteryRealtime, int which) {
return mBluetoothOnTimer.getTotalTimeLocked(batteryRealtime, which);
}
+ @Override public long getBluetoothStateTime(int bluetoothState,
+ long batteryRealtime, int which) {
+ return mBluetoothStateTimer[bluetoothState].getTotalTimeLocked(
+ batteryRealtime, which);
+ }
+
+ @Override public int getBluetoothStateCount(int bluetoothState, int which) {
+ return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
+ }
+
@Override
public long getNetworkActivityBytes(int type, int which) {
if (type >= 0 && type < mNetworkByteActivityCounters.length) {
@@ -3115,67 +3220,67 @@
}
@Override
- public void noteWifiRunningLocked() {
+ public void noteWifiRunningLocked(long elapsedRealtime) {
if (!mWifiRunning) {
mWifiRunning = true;
if (mWifiRunningTimer == null) {
mWifiRunningTimer = new StopwatchTimer(Uid.this, WIFI_RUNNING,
mWifiRunningTimers, mUnpluggables);
}
- mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this);
+ mWifiRunningTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteWifiStoppedLocked() {
+ public void noteWifiStoppedLocked(long elapsedRealtime) {
if (mWifiRunning) {
mWifiRunning = false;
- mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mWifiRunningTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteFullWifiLockAcquiredLocked() {
+ public void noteFullWifiLockAcquiredLocked(long elapsedRealtime) {
if (!mFullWifiLockOut) {
mFullWifiLockOut = true;
if (mFullWifiLockTimer == null) {
mFullWifiLockTimer = new StopwatchTimer(Uid.this, FULL_WIFI_LOCK,
mFullWifiLockTimers, mUnpluggables);
}
- mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this);
+ mFullWifiLockTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteFullWifiLockReleasedLocked() {
+ public void noteFullWifiLockReleasedLocked(long elapsedRealtime) {
if (mFullWifiLockOut) {
mFullWifiLockOut = false;
- mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mFullWifiLockTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteWifiScanStartedLocked() {
+ public void noteWifiScanStartedLocked(long elapsedRealtime) {
if (!mWifiScanStarted) {
mWifiScanStarted = true;
if (mWifiScanTimer == null) {
mWifiScanTimer = new StopwatchTimer(Uid.this, WIFI_SCAN,
mWifiScanTimers, mUnpluggables);
}
- mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this);
+ mWifiScanTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteWifiScanStoppedLocked() {
+ public void noteWifiScanStoppedLocked(long elapsedRealtime) {
if (mWifiScanStarted) {
mWifiScanStarted = false;
- mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mWifiScanTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteWifiBatchedScanStartedLocked(int csph) {
+ public void noteWifiBatchedScanStartedLocked(int csph, long elapsedRealtime) {
int bin = 0;
while (csph > 8 && bin < NUM_WIFI_BATCHED_SCAN_BINS) {
csph = csph >> 3;
@@ -3186,41 +3291,41 @@
if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
- stopRunningLocked(BatteryStatsImpl.this);
+ stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
mWifiBatchedScanBinStarted = bin;
if (mWifiBatchedScanTimer[bin] == null) {
makeWifiBatchedScanBin(bin, null);
}
- mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this);
+ mWifiBatchedScanTimer[bin].startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
@Override
- public void noteWifiBatchedScanStoppedLocked() {
+ public void noteWifiBatchedScanStoppedLocked(long elapsedRealtime) {
if (mWifiBatchedScanBinStarted != NO_BATCHED_SCAN_STARTED) {
mWifiBatchedScanTimer[mWifiBatchedScanBinStarted].
- stopRunningLocked(BatteryStatsImpl.this);
+ stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
mWifiBatchedScanBinStarted = NO_BATCHED_SCAN_STARTED;
}
}
@Override
- public void noteWifiMulticastEnabledLocked() {
+ public void noteWifiMulticastEnabledLocked(long elapsedRealtime) {
if (!mWifiMulticastEnabled) {
mWifiMulticastEnabled = true;
if (mWifiMulticastTimer == null) {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mUnpluggables);
}
- mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this);
+ mWifiMulticastTimer.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@Override
- public void noteWifiMulticastDisabledLocked() {
+ public void noteWifiMulticastDisabledLocked(long elapsedRealtime) {
if (mWifiMulticastEnabled) {
mWifiMulticastEnabled = false;
- mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mWifiMulticastTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@@ -3233,19 +3338,20 @@
}
@Override
- public void noteAudioTurnedOnLocked() {
+ public void noteAudioTurnedOnLocked(long elapsedRealtime) {
if (!mAudioTurnedOn) {
mAudioTurnedOn = true;
- createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+ createAudioTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this,
+ elapsedRealtime);
}
}
@Override
- public void noteAudioTurnedOffLocked() {
+ public void noteAudioTurnedOffLocked(long elapsedRealtime) {
if (mAudioTurnedOn) {
mAudioTurnedOn = false;
if (mAudioTurnedOnTimer != null) {
- mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mAudioTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
}
@@ -3259,19 +3365,20 @@
}
@Override
- public void noteVideoTurnedOnLocked() {
+ public void noteVideoTurnedOnLocked(long elapsedRealtime) {
if (!mVideoTurnedOn) {
mVideoTurnedOn = true;
- createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+ createVideoTurnedOnTimerLocked().startRunningLocked(BatteryStatsImpl.this,
+ elapsedRealtime);
}
}
@Override
- public void noteVideoTurnedOffLocked() {
+ public void noteVideoTurnedOffLocked(long elapsedRealtime) {
if (mVideoTurnedOn) {
mVideoTurnedOn = false;
if (mVideoTurnedOnTimer != null) {
- mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mVideoTurnedOnTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
}
@@ -3285,15 +3392,16 @@
}
@Override
- public void noteActivityResumedLocked() {
+ public void noteActivityResumedLocked(long elapsedRealtime) {
// We always start, since we want multiple foreground PIDs to nest
- createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this);
+ createForegroundActivityTimerLocked().startRunningLocked(BatteryStatsImpl.this,
+ elapsedRealtime);
}
@Override
- public void noteActivityPausedLocked() {
+ public void noteActivityPausedLocked(long elapsedRealtime) {
if (mForegroundActivityTimer != null) {
- mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this);
+ mForegroundActivityTimer.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@@ -4870,28 +4978,28 @@
return t;
}
- public void noteStartWakeLocked(int pid, String name, int type) {
+ public void noteStartWakeLocked(int pid, String name, int type, long elapsedRealtime) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
- t.startRunningLocked(BatteryStatsImpl.this);
+ t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
Pid p = getPidStatsLocked(pid);
if (p.mWakeStart == 0) {
- p.mWakeStart = SystemClock.elapsedRealtime();
+ p.mWakeStart = elapsedRealtime;
}
}
}
- public void noteStopWakeLocked(int pid, String name, int type) {
+ public void noteStopWakeLocked(int pid, String name, int type, long elapsedRealtime) {
StopwatchTimer t = getWakeTimerLocked(name, type);
if (t != null) {
- t.stopRunningLocked(BatteryStatsImpl.this);
+ t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
if (pid >= 0 && type == WAKE_TYPE_PARTIAL) {
Pid p = mPids.get(pid);
if (p != null && p.mWakeStart != 0) {
- p.mWakeSum += SystemClock.elapsedRealtime() - p.mWakeStart;
+ p.mWakeSum += elapsedRealtime - p.mWakeStart;
p.mWakeStart = 0;
}
}
@@ -4911,32 +5019,32 @@
}
}
- public void noteStartSensor(int sensor) {
+ public void noteStartSensor(int sensor, long elapsedRealtime) {
StopwatchTimer t = getSensorTimerLocked(sensor, true);
if (t != null) {
- t.startRunningLocked(BatteryStatsImpl.this);
+ t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
- public void noteStopSensor(int sensor) {
+ public void noteStopSensor(int sensor, long elapsedRealtime) {
// Don't create a timer if one doesn't already exist
StopwatchTimer t = getSensorTimerLocked(sensor, false);
if (t != null) {
- t.stopRunningLocked(BatteryStatsImpl.this);
+ t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
- public void noteStartGps() {
+ public void noteStartGps(long elapsedRealtime) {
StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, true);
if (t != null) {
- t.startRunningLocked(BatteryStatsImpl.this);
+ t.startRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
- public void noteStopGps() {
+ public void noteStopGps(long elapsedRealtime) {
StopwatchTimer t = getSensorTimerLocked(Sensor.GPS, false);
if (t != null) {
- t.stopRunningLocked(BatteryStatsImpl.this);
+ t.stopRunningLocked(BatteryStatsImpl.this, elapsedRealtime);
}
}
@@ -4966,9 +5074,16 @@
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables);
}
+ mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables);
mWifiOnTimer = new StopwatchTimer(null, -3, null, mUnpluggables);
mGlobalWifiRunningTimer = new StopwatchTimer(null, -4, null, mUnpluggables);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ mWifiStateTimer[i] = new StopwatchTimer(null, -600-i, null, mUnpluggables);
+ }
mBluetoothOnTimer = new StopwatchTimer(null, -5, null, mUnpluggables);
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mUnpluggables);
+ }
mAudioOnTimer = new StopwatchTimer(null, -6, null, mUnpluggables);
mVideoOnTimer = new StopwatchTimer(null, -7, null, mUnpluggables);
mOnBattery = mOnBatteryInternal = false;
@@ -5225,9 +5340,16 @@
mNetworkByteActivityCounters[i].reset(false);
mNetworkPacketActivityCounters[i].reset(false);
}
+ mMobileRadioActiveTimer.reset(this, false);
mWifiOnTimer.reset(this, false);
mGlobalWifiRunningTimer.reset(this, false);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ mWifiStateTimer[i].reset(this, false);
+ }
mBluetoothOnTimer.reset(this, false);
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ mBluetoothStateTimer[i].reset(this, false);
+ }
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset()) {
@@ -5484,33 +5606,31 @@
private void updateNetworkActivityLocked() {
if (!SystemProperties.getBoolean(PROP_QTAGUID_ENABLED, false)) return;
- final NetworkStats snapshot;
- try {
- snapshot = mNetworkStatsFactory.readNetworkStatsDetail();
- } catch (IOException e) {
- Log.wtf(TAG, "Failed to read network stats", e);
- return;
- }
+ if (mMobileIfaces.length > 0) {
+ final NetworkStats snapshot;
+ final NetworkStats last = mCurMobileSnapshot;
+ try {
+ snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
+ mMobileIfaces, NetworkStats.TAG_NONE, mLastMobileSnapshot);
+ } catch (IOException e) {
+ Log.wtf(TAG, "Failed to read mobile network stats", e);
+ return;
+ }
- if (mLastSnapshot == null) {
- mLastSnapshot = snapshot;
- return;
- }
+ mCurMobileSnapshot = snapshot;
+ mLastMobileSnapshot = last;
- final NetworkStats delta = snapshot.subtract(mLastSnapshot);
- mLastSnapshot = snapshot;
+ final NetworkStats delta = NetworkStats.subtract(snapshot, last,
+ null, null, mTmpNetworkStats);
+ mTmpNetworkStats = delta;
- NetworkStats.Entry entry = null;
- final int size = delta.size();
- for (int i = 0; i < size; i++) {
- entry = delta.getValues(i, entry);
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
- if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
- if (entry.tag != NetworkStats.TAG_NONE) continue;
+ if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
- final Uid u = getUidStatsLocked(entry.uid);
-
- if (mMobileIfaces.contains(entry.iface)) {
+ final Uid u = getUidStatsLocked(entry.uid);
u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
entry.rxPackets);
u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes,
@@ -5522,8 +5642,42 @@
entry.rxPackets);
mNetworkPacketActivityCounters[NETWORK_MOBILE_TX_DATA].addCountLocked(
entry.txPackets);
+ }
+ }
- } else if (mWifiIfaces.contains(entry.iface)) {
+ if (mWifiIfaces.length > 0) {
+ final NetworkStats snapshot;
+ final NetworkStats last = mCurWifiSnapshot;
+ try {
+ snapshot = mNetworkStatsFactory.readNetworkStatsDetail(UID_ALL,
+ mWifiIfaces, NetworkStats.TAG_NONE, mLastWifiSnapshot);
+ } catch (IOException e) {
+ Log.wtf(TAG, "Failed to read wifi network stats", e);
+ return;
+ }
+
+ mCurWifiSnapshot = snapshot;
+ mLastWifiSnapshot = last;
+
+ final NetworkStats delta = NetworkStats.subtract(snapshot, last,
+ null, null, mTmpNetworkStats);
+ mTmpNetworkStats = delta;
+ mLastWifiSnapshot = snapshot;
+
+ final int size = delta.size();
+ for (int i = 0; i < size; i++) {
+ final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
+
+ if (DEBUG) {
+ final NetworkStats.Entry cur = snapshot.getValues(i, null);
+ Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
+ + " tx=" + entry.txBytes + ", cur rx=" + cur.rxBytes
+ + " tx=" + cur.txBytes);
+ }
+
+ if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+
+ final Uid u = getUidStatsLocked(entry.uid);
u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes, entry.rxPackets);
u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, entry.txPackets);
@@ -5939,7 +6093,7 @@
stream.close();
readSummaryFromParcel(in);
- } catch(java.io.IOException e) {
+ } catch(Exception e) {
Slog.e("BatteryStats", "Error reading battery statistics", e);
}
@@ -6119,12 +6273,20 @@
mNetworkByteActivityCounters[i].readSummaryFromParcelLocked(in);
mNetworkPacketActivityCounters[i].readSummaryFromParcelLocked(in);
}
+ mMobileRadioActive = false;
+ mMobileRadioActiveTimer.readSummaryFromParcelLocked(in);
mWifiOn = false;
mWifiOnTimer.readSummaryFromParcelLocked(in);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer.readSummaryFromParcelLocked(in);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ mWifiStateTimer[i].readSummaryFromParcelLocked(in);
+ }
mBluetoothOn = false;
mBluetoothOnTimer.readSummaryFromParcelLocked(in);
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
+ }
int NKW = in.readInt();
if (NKW > 10000) {
@@ -6139,6 +6301,9 @@
}
sNumSpeedSteps = in.readInt();
+ if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) {
+ throw new BadParcelableException("Bad speed steps in data: " + sNumSpeedSteps);
+ }
final int NU = in.readInt();
if (NU > 10000) {
@@ -6340,9 +6505,16 @@
mNetworkByteActivityCounters[i].writeSummaryFromParcelLocked(out);
mNetworkPacketActivityCounters[i].writeSummaryFromParcelLocked(out);
}
+ mMobileRadioActiveTimer.writeSummaryFromParcelLocked(out, NOWREAL);
mWifiOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
mGlobalWifiRunningTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ mWifiStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+ }
mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL);
+ }
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
@@ -6574,12 +6746,22 @@
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mUnpluggables, in);
}
+ mMobileRadioActive = false;
+ mMobileRadioActiveTimer = new StopwatchTimer(null, -400, null, mUnpluggables, in);
mWifiOn = false;
mWifiOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
mGlobalWifiRunning = false;
mGlobalWifiRunningTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ mWifiStateTimer[i] = new StopwatchTimer(null, -600-i,
+ null, mUnpluggables, in);
+ }
mBluetoothOn = false;
mBluetoothOnTimer = new StopwatchTimer(null, -2, null, mUnpluggables, in);
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
+ null, mUnpluggables, in);
+ }
mUptime = in.readLong();
mUptimeStart = in.readLong();
mLastUptime = 0;
@@ -6604,9 +6786,6 @@
mDischargeAmountScreenOffSinceCharge = in.readInt();
mLastWriteTime = in.readLong();
- mRadioDataUptime = in.readLong();
- mRadioDataStart = -1;
-
mBluetoothPingCount = in.readInt();
mBluetoothPingStart = -1;
@@ -6685,9 +6864,16 @@
mNetworkByteActivityCounters[i].writeToParcel(out);
mNetworkPacketActivityCounters[i].writeToParcel(out);
}
+ mMobileRadioActiveTimer.writeToParcel(out, batteryRealtime);
mWifiOnTimer.writeToParcel(out, batteryRealtime);
mGlobalWifiRunningTimer.writeToParcel(out, batteryRealtime);
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ mWifiStateTimer[i].writeToParcel(out, batteryRealtime);
+ }
mBluetoothOnTimer.writeToParcel(out, batteryRealtime);
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ mBluetoothStateTimer[i].writeToParcel(out, batteryRealtime);
+ }
out.writeLong(mUptime);
out.writeLong(mUptimeStart);
out.writeLong(mRealtime);
@@ -6709,9 +6895,6 @@
out.writeInt(mDischargeAmountScreenOffSinceCharge);
out.writeLong(mLastWriteTime);
- // Write radio uptime for data
- out.writeLong(getRadioDataUptime());
-
out.writeInt(getBluetoothPingCount());
if (inclUids) {
@@ -6786,12 +6969,22 @@
pr.println("*** Data connection type #" + i + ":");
mPhoneDataConnectionsTimer[i].logState(pr, " ");
}
+ pr.println("*** Mobile network active timer:");
+ mMobileRadioActiveTimer.logState(pr, " ");
pr.println("*** Wifi timer:");
mWifiOnTimer.logState(pr, " ");
pr.println("*** WifiRunning timer:");
mGlobalWifiRunningTimer.logState(pr, " ");
+ for (int i=0; i<NUM_WIFI_STATES; i++) {
+ pr.println("*** Wifi state #" + i + ":");
+ mWifiStateTimer[i].logState(pr, " ");
+ }
pr.println("*** Bluetooth timer:");
mBluetoothOnTimer.logState(pr, " ");
+ for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
+ pr.println("*** Bluetooth active type #" + i + ":");
+ mBluetoothStateTimer[i].logState(pr, " ");
+ }
}
super.dumpLocked(context, pw, isUnpluggedOnly, reqUid, historyOnly);
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4f3b5b3..f9a1f89 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -224,9 +224,37 @@
ZygoteInit.setCloseOnExec(serverPipeFd, true);
}
+ /**
+ * In order to avoid leaking descriptors to the Zygote child,
+ * the native code must close the two Zygote socket descriptors
+ * in the child process before it switches from Zygote-root to
+ * the UID and privileges of the application being launched.
+ *
+ * In order to avoid "bad file descriptor" errors when the
+ * two LocalSocket objects are closed, the Posix file
+ * descriptors are released via a dup2() call which closes
+ * the socket and substitutes an open descriptor to /dev/null.
+ */
+
+ int [] fdsToClose = { -1, -1 };
+
+ FileDescriptor fd = mSocket.getFileDescriptor();
+
+ if (fd != null) {
+ fdsToClose[0] = fd.getInt$();
+ }
+
+ fd = ZygoteInit.getServerSocketFileDescriptor();
+
+ if (fd != null) {
+ fdsToClose[1] = fd.getInt$();
+ }
+
+ fd = null;
+
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
- parsedArgs.niceName);
+ parsedArgs.niceName, fdsToClose);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
@@ -814,6 +842,12 @@
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
+ /**
+ * By the time we get here, the native code has closed the two actual Zygote
+ * socket connections, and substituted /dev/null in their place. The LocalSocket
+ * objects still need to be closed properly.
+ */
+
closeSocket();
ZygoteInit.closeServerSocket();
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9dc9116..bf62745 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -207,6 +207,16 @@
sServerSocket = null;
}
+ /**
+ * Return the server socket's underlying file descriptor, so that
+ * ZygoteConnection can pass it to the native code for proper
+ * closure after a child process is forked off.
+ */
+
+ static FileDescriptor getServerSocketFileDescriptor() {
+ return sServerSocket.getFileDescriptor();
+ }
+
private static final int UNPRIVILEGED_UID = 9999;
private static final int UNPRIVILEGED_GID = 9999;
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index 03fa9b4..c2d22dd 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ActionMode;
@@ -50,7 +51,8 @@
public ActionBarContainer(Context context, AttributeSet attrs) {
super(context, attrs);
- setBackgroundDrawable(null);
+ // Set a transparent background so that we project appropriately.
+ setBackground(new ActionBarBackgroundDrawable());
TypedArray a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.ActionBar);
@@ -242,24 +244,6 @@
}
@Override
- public void onDraw(Canvas canvas) {
- if (getWidth() == 0 || getHeight() == 0) {
- return;
- }
-
- if (mIsSplit) {
- if (mSplitBackground != null) mSplitBackground.draw(canvas);
- } else {
- if (mBackground != null) {
- mBackground.draw(canvas);
- }
- if (mStackedBackground != null && mIsStacked) {
- mStackedBackground.draw(canvas);
- }
- }
- }
-
- @Override
public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
// No starting an action mode for an action bar child! (Where would it go?)
return null;
@@ -290,12 +274,13 @@
public void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
- final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE;
+ final View tabContainer = mTabContainer;
+ final boolean hasTabs = tabContainer != null && tabContainer.getVisibility() != GONE;
- if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
+ if (tabContainer != null && tabContainer.getVisibility() != GONE) {
final int containerHeight = getMeasuredHeight();
- final int tabHeight = mTabContainer.getMeasuredHeight();
- mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
+ final int tabHeight = tabContainer.getMeasuredHeight();
+ tabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
}
boolean needsInvalidate = false;
@@ -306,13 +291,15 @@
}
} else {
if (mBackground != null) {
- mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
- mActionBarView.getRight(), mActionBarView.getBottom());
+ final ActionBarView actionBarView = mActionBarView;
+ mBackground.setBounds(actionBarView.getLeft(), actionBarView.getTop(),
+ actionBarView.getRight(), actionBarView.getBottom());
needsInvalidate = true;
}
- if ((mIsStacked = hasTabs && mStackedBackground != null)) {
- mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
- mTabContainer.getRight(), mTabContainer.getBottom());
+ mIsStacked = hasTabs;
+ if (hasTabs && mStackedBackground != null) {
+ mStackedBackground.setBounds(tabContainer.getLeft(), tabContainer.getTop(),
+ tabContainer.getRight(), tabContainer.getBottom());
needsInvalidate = true;
}
}
@@ -321,4 +308,37 @@
invalidate();
}
}
+
+ /**
+ * Dummy drawable so that we don't break background display lists and
+ * projection surfaces.
+ */
+ private class ActionBarBackgroundDrawable extends Drawable {
+ @Override
+ public void draw(Canvas canvas) {
+ if (mIsSplit) {
+ if (mSplitBackground != null) mSplitBackground.draw(canvas);
+ } else {
+ if (mBackground != null) {
+ mBackground.draw(canvas);
+ }
+ if (mStackedBackground != null && mIsStacked) {
+ mStackedBackground.draw(canvas);
+ }
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3419f15..f5c18f5 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -30,10 +30,12 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.storage.IMountService;
+import android.os.storage.StorageManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.view.IWindowManager;
import android.view.View;
import android.widget.Button;
@@ -498,6 +500,13 @@
getLockSettings().setLockPattern(patternToString(pattern), getCurrentOrCallingUserId());
DevicePolicyManager dpm = getDevicePolicyManager();
if (pattern != null) {
+
+ int userHandle = getCurrentOrCallingUserId();
+ if (userHandle == UserHandle.USER_OWNER) {
+ String stringPattern = patternToString(pattern);
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern);
+ }
+
setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
if (!isFallback) {
deleteGallery();
@@ -565,7 +574,7 @@
}
/** Update the encryption password if it is enabled **/
- private void updateEncryptionPassword(String password) {
+ private void updateEncryptionPassword(int type, String password) {
DevicePolicyManager dpm = getDevicePolicyManager();
if (dpm.getStorageEncryptionStatus(getCurrentOrCallingUserId())
!= DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE) {
@@ -580,7 +589,7 @@
IMountService mountService = IMountService.Stub.asInterface(service);
try {
- mountService.changeEncryptionPassword(password);
+ mountService.changeEncryptionPassword(type, password);
} catch (RemoteException e) {
Log.e(TAG, "Error changing encryption password", e);
}
@@ -623,12 +632,15 @@
getLockSettings().setLockPassword(password, userHandle);
DevicePolicyManager dpm = getDevicePolicyManager();
if (password != null) {
+ int computedQuality = computePasswordQuality(password);
+
if (userHandle == UserHandle.USER_OWNER) {
// Update the encryption password.
- updateEncryptionPassword(password);
+ int type = computedQuality == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+ ? StorageManager.CRYPT_TYPE_PIN : StorageManager.CRYPT_TYPE_PASSWORD;
+ updateEncryptionPassword(type, password);
}
- int computedQuality = computePasswordQuality(password);
if (!isFallback) {
deleteGallery();
setLong(PASSWORD_TYPE_KEY, Math.max(quality, computedQuality), userHandle);
@@ -675,8 +687,7 @@
0, 0, 0, 0, 0, 0, 0, userHandle);
}
// Add the password to the password history. We assume all
- // password
- // hashes have the same length for simplicity of implementation.
+ // password hashes have the same length for simplicity of implementation.
String passwordHistory = getString(PASSWORD_HISTORY_KEY, userHandle);
if (passwordHistory == null) {
passwordHistory = new String();
@@ -695,6 +706,11 @@
}
setString(PASSWORD_HISTORY_KEY, passwordHistory, userHandle);
} else {
+ if (userHandle == UserHandle.USER_OWNER) {
+ // Update the encryption password.
+ updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, password);
+ }
+
dpm.setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0,
userHandle);
diff --git a/core/java/com/android/server/SystemService.java b/core/java/com/android/server/SystemService.java
index 0c89f94..e374563 100644
--- a/core/java/com/android/server/SystemService.java
+++ b/core/java/com/android/server/SystemService.java
@@ -49,9 +49,32 @@
* Boot Phases
*/
public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?
+
+ /**
+ * After receiving this boot phase, services can obtain lock settings data.
+ */
public static final int PHASE_LOCK_SETTINGS_READY = 480;
+
+ /**
+ * After receiving this boot phase, services can safely call into core system services
+ * such as the PowerManager or PackageManager.
+ */
public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+
+ /**
+ * After receiving this boot phase, services can broadcast Intents.
+ */
+ public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
+
+ /**
+ * After receiving this boot phase, services can start/bind to third party apps.
+ * Apps will be able to make Binder calls into services at this point.
+ */
public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+
+ /**
+ * After receiving this boot phase, services must have finished all boot-related work.
+ */
public static final int PHASE_BOOT_COMPLETE = 1000;
private final Context mContext;
@@ -85,14 +108,6 @@
}
/**
- * Services are not yet available. This is a good place to do setup work that does
- * not require other services.
- *
- * @param context The system context.
- */
- public void onCreate(Context context) {}
-
- /**
* Called when the dependencies listed in the @Service class-annotation are available
* and after the chosen start phase.
* When this method returns, the service should be published.
diff --git a/core/java/com/android/server/SystemServiceManager.java b/core/java/com/android/server/SystemServiceManager.java
index 6c853be..eb8df0e 100644
--- a/core/java/com/android/server/SystemServiceManager.java
+++ b/core/java/com/android/server/SystemServiceManager.java
@@ -45,18 +45,13 @@
}
/**
- * Starts a service by name if the class exists, otherwise ignores it.
+ * Starts a service by class name.
*
- * @return The service instance, or null if not found.
+ * @return The service instance.
*/
@SuppressWarnings("unchecked")
- public SystemService startServiceIfExists(String className) {
- try {
- return startService((Class<SystemService>)Class.forName(className));
- } catch (ClassNotFoundException cnfe) {
- Slog.i(TAG, className + " not available, ignoring.");
- return null;
- }
+ public SystemService startService(String className) throws ClassNotFoundException {
+ return startService((Class<SystemService>) Class.forName(className));
}
/**
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index d8041c5..5056c57 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -136,7 +136,6 @@
android_hardware_UsbDevice.cpp \
android_hardware_UsbDeviceConnection.cpp \
android_hardware_UsbRequest.cpp \
- android_debug_JNITest.cpp \
android_util_FileObserver.cpp \
android/opengl/poly_clip.cpp.arm \
android/opengl/util.cpp.arm \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 77c5c18..5bde80d 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -133,7 +133,6 @@
extern int register_android_database_SQLiteConnection(JNIEnv* env);
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
extern int register_android_database_SQLiteDebug(JNIEnv* env);
-extern int register_android_debug_JNITest(JNIEnv* env);
extern int register_android_nio_utils(JNIEnv* env);
extern int register_android_text_format_Time(JNIEnv* env);
extern int register_android_os_Debug(JNIEnv* env);
@@ -761,13 +760,6 @@
mOptions.add(opt);
}
- /*
- * We don't have /tmp on the device, but we often have an SD card. Apps
- * shouldn't use this, but some test suites might want to exercise it.
- */
- opt.optionString = "-Djava.io.tmpdir=/sdcard";
- mOptions.add(opt);
-
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
@@ -1102,7 +1094,6 @@
}
static const RegJNIRec gRegJNI[] = {
- REG_JNI(register_android_debug_JNITest),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 24160ab..310966c 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -466,7 +466,6 @@
} else {
bitmap->setAlphaType(kUnpremul_SkAlphaType);
}
- bitmap->setIsOpaque(!hasAlpha);
}
static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -628,7 +627,7 @@
}
return GraphicsJNI::createBitmap(env, dst, allocator.getStorageObj(),
- GraphicsJNI::kBitmapCreateFlag_Mutable, NULL, NULL);
+ getPremulBitmapCreateFlags(true), NULL, NULL);
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index fae93ba..e8feacb 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -125,12 +125,18 @@
static SkPixelRef* installPixelRef(SkBitmap* bitmap, SkStreamRewindable* stream,
int sampleSize, bool ditherImage) {
+ SkImageInfo bitmapInfo;
+ if (!bitmap->asImageInfo(&bitmapInfo)) {
+ ALOGW("bitmap has unknown configuration so no memory has been allocated");
+ return NULL;
+ }
+
SkImageRef* pr;
// only use ashmem for large images, since mmaps come at a price
if (bitmap->getSize() >= 32 * 1024) {
- pr = new SkImageRef_ashmem(stream, bitmap->config(), sampleSize);
+ pr = new SkImageRef_ashmem(bitmapInfo, stream, sampleSize);
} else {
- pr = new SkImageRef_GlobalPool(stream, bitmap->config(), sampleSize);
+ pr = new SkImageRef_GlobalPool(bitmapInfo, stream, sampleSize);
}
pr->setDitherImage(ditherImage);
bitmap->setPixelRef(pr)->unref();
@@ -192,8 +198,15 @@
return false;
}
+ SkImageInfo bitmapInfo;
+ if (!bitmap->asImageInfo(&bitmapInfo)) {
+ ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
+ return false;
+ }
+
// Create a new pixelref with the new ctable that wraps the previous pixelref
- SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef), ctable);
+ SkPixelRef* pr = new AndroidPixelRef(*static_cast<AndroidPixelRef*>(mPixelRef),
+ bitmapInfo, bitmap->rowBytes(), ctable);
bitmap->setPixelRef(pr)->unref();
// since we're already allocated, we lockPixels right away
@@ -418,7 +431,7 @@
}
SkPaint paint;
- paint.setFilterBitmap(true);
+ paint.setFilterLevel(SkPaint::kLow_FilterLevel);
SkCanvas canvas(*outputBitmap);
canvas.scale(sx, sy);
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index e98d45b..7420055 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -555,7 +555,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterBitmap(true);
+ filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
} else {
canvas->drawBitmap(*bitmap, left_, top_, paint);
@@ -570,7 +570,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterBitmap(true);
+ filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint);
@@ -593,7 +593,7 @@
if (paint) {
filteredPaint = *paint;
}
- filteredPaint.setFilterBitmap(true);
+ filteredPaint.setFilterLevel(SkPaint::kLow_FilterLevel);
canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
} else {
canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 66f9f3d..98edbdb 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -444,8 +444,9 @@
///////////////////////////////////////////////////////////////////////////////
-AndroidPixelRef::AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,
- SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable, (storageObj == NULL)),
+AndroidPixelRef::AndroidPixelRef(JNIEnv* env, const SkImageInfo& info, void* storage,
+ size_t rowBytes, jbyteArray storageObj, SkColorTable* ctable) :
+ SkMallocPixelRef(info, storage, rowBytes, ctable, (storageObj == NULL)),
fWrappedPixelRef(NULL) {
SkASSERT(storage);
SkASSERT(env);
@@ -463,10 +464,11 @@
}
-AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable) :
- SkMallocPixelRef(wrappedPixelRef.getAddr(), wrappedPixelRef.getSize(), ctable, false),
+AndroidPixelRef::AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImageInfo& info,
+ size_t rowBytes, SkColorTable* ctable) :
+ SkMallocPixelRef(info, wrappedPixelRef.getAddr(), rowBytes, ctable, false),
fWrappedPixelRef(wrappedPixelRef.fWrappedPixelRef ?
- wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef)
+ wrappedPixelRef.fWrappedPixelRef : &wrappedPixelRef)
{
SkASSERT(fWrappedPixelRef);
SkSafeRef(fWrappedPixelRef);
@@ -568,6 +570,14 @@
"bitmap size exceeds 32bits");
return NULL;
}
+
+ SkImageInfo bitmapInfo;
+ if (!bitmap->asImageInfo(&bitmapInfo)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "unknown bitmap configuration");
+ return NULL;
+ }
+
size_t size = size64.get32();
jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
gVMRuntime_newNonMovableArray,
@@ -581,7 +591,8 @@
return NULL;
}
SkASSERT(addr);
- SkPixelRef* pr = new AndroidPixelRef(env, (void*) addr, size, arrayObj, ctable);
+ SkPixelRef* pr = new AndroidPixelRef(env, bitmapInfo, (void*) addr,
+ bitmap->rowBytes(), arrayObj, ctable);
bitmap->setPixelRef(pr)->unref();
// since we're already allocated, we lockPixels right away
// HeapAllocator behaves this way too
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 5f29604..cb154aa 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -92,15 +92,16 @@
class AndroidPixelRef : public SkMallocPixelRef {
public:
- AndroidPixelRef(JNIEnv* env, void* storage, size_t size, jbyteArray storageObj,
- SkColorTable* ctable);
+ AndroidPixelRef(JNIEnv* env, const SkImageInfo& info, void* storage, size_t rowBytes,
+ jbyteArray storageObj, SkColorTable* ctable);
/**
* Creates an AndroidPixelRef that wraps (and refs) another to reuse/share
* the same storage and java byte array refcounting, yet have a different
* color table.
*/
- AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, SkColorTable* ctable);
+ AndroidPixelRef(AndroidPixelRef& wrappedPixelRef, const SkImageInfo& info,
+ size_t rowBytes, SkColorTable* ctable);
virtual ~AndroidPixelRef();
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 6c81f06..189fe47 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -155,7 +155,8 @@
static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
NPE_CHECK_RETURN_VOID(env, paint);
- GraphicsJNI::getNativePaint(env, paint)->setFilterBitmap(filterBitmap);
+ GraphicsJNI::getNativePaint(env, paint)->setFilterLevel(
+ filterBitmap ? SkPaint::kLow_FilterLevel : SkPaint::kNone_FilterLevel);
}
static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index bcf1273..912968a 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -214,7 +214,7 @@
SkRegion* region = new SkRegion;
size_t size = p->readInt32();
- region->readFromMemory(p->readInplace(size));
+ region->readFromMemory(p->readInplace(size), size);
return reinterpret_cast<jlong>(region);
}
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index eb416cb..a134d4b 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -52,7 +52,6 @@
}
SkStreamRewindable* AssetStreamAdaptor::duplicate() const {
- SkASSERT(false);
// Cannot create a duplicate, since each AssetStreamAdaptor
// would be modifying the Asset.
//return new AssetStreamAdaptor(fAsset);
diff --git a/core/jni/android_debug_JNITest.cpp b/core/jni/android_debug_JNITest.cpp
deleted file mode 100644
index 9147284..0000000
--- a/core/jni/android_debug_JNITest.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/* //device/libs/android_runtime/android_debug_JNITest.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "DebugJNI"
-
-#include "jni.h"
-#include "nativehelper/JNIHelp.h"
-#include "utils/Log.h"
-#include "utils/misc.h"
-//#include "android_runtime/AndroidRuntime.h"
-
-namespace android {
-
-/*
- * Implements:
- * native int part1(int intArg, double doubleArg, String stringArg,
- * int[] arrayArg)
- */
-static jint android_debug_JNITest_part1(JNIEnv* env, jobject object,
- jint intArg, jdouble doubleArg, jstring stringArg, jobjectArray arrayArg)
-{
- jclass clazz;
- jmethodID part2id;
- jsize arrayLen;
- jint arrayVal;
- int result = -2;
-
- ALOGI("JNI test: in part1, intArg=%d, doubleArg=%.3f\n", intArg, doubleArg);
-
- /* find "int part2(double doubleArg, int fromArray, String stringArg)" */
- clazz = env->GetObjectClass(object);
- part2id = env->GetMethodID(clazz,
- "part2", "(DILjava/lang/String;)I");
- if (part2id == NULL) {
- ALOGE("JNI test: unable to find part2\n");
- return -1;
- }
-
- /* get the length of the array */
- arrayLen = env->GetArrayLength(arrayArg);
- ALOGI(" array size is %d\n", arrayLen);
-
- /*
- * Get the last element in the array.
- * Use the Get<type>ArrayElements functions instead if you need access
- * to multiple elements.
- */
- arrayVal = (int) env->GetObjectArrayElement(arrayArg, arrayLen-1);
- ALOGI(" array val is %d\n", arrayVal);
-
- /* call this->part2 */
- result = env->CallIntMethod(object, part2id,
- doubleArg, arrayVal, stringArg);
-
- return result;
-}
-
-/*
- * Implements:
- * private static native int part3(String stringArg);
- */
-static jint android_debug_JNITest_part3(JNIEnv* env, jclass clazz,
- jstring stringArg)
-{
- const char* utfChars;
- jboolean isCopy;
-
- ALOGI("JNI test: in part3\n");
-
- utfChars = env->GetStringUTFChars(stringArg, &isCopy);
-
- ALOGI(" String is '%s', isCopy=%d\n", (const char*) utfChars, isCopy);
-
- env->ReleaseStringUTFChars(stringArg, utfChars);
-
- return 2000;
-}
-
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "part1", "(IDLjava/lang/String;[I)I",
- (void*) android_debug_JNITest_part1 },
- { "part3", "(Ljava/lang/String;)I",
- (void*) android_debug_JNITest_part3 },
-};
-int register_android_debug_JNITest(JNIEnv* env)
-{
- return jniRegisterNativeMethods(env, "android/debug/JNITest",
- gMethods, NELEM(gMethods));
-}
-
-#if 0
-/* trampoline into C++ */
-extern "C"
-int register_android_debug_JNITest_C(JNIEnv* env)
-{
- return android::register_android_debug_JNITest(env);
-}
-#endif
-
-}; // namespace android
-
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 5b0a4b2..bf65dfc 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -69,22 +69,22 @@
jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
- egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getHandle", "()I");
- eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getHandle", "()I");
- eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getHandle", "()I");
- eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getHandle", "()I");
+ egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+ eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+ eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+ eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
- egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(I)V");
- eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(I)V");
- eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(I)V");
- eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(I)V");
+ egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+ eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+ eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+ eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
- jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, (jint)EGL_NO_CONTEXT);
+ jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
- jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, (jint)EGL_NO_DISPLAY);
+ jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
- jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, (jint)EGL_NO_SURFACE);
+ jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
@@ -106,7 +106,8 @@
"Object is set to null.");
}
- return (void*) (_env->CallIntMethod(obj, mid));
+ jlong handle = _env->CallLongMethod(obj, mid);
+ return reinterpret_cast<void*>(handle);
}
static jobject
@@ -126,7 +127,7 @@
return eglNoSurfaceObject;
}
- return _env->NewObject(cls, con, (jint)handle);
+ return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
}
// --------------------------------------------------------------------------
@@ -142,14 +143,26 @@
/* EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) */
static jobject
android_eglGetDisplay
- (JNIEnv *_env, jobject _this, jint display_id) {
+ (JNIEnv *_env, jobject _this, jlong display_id) {
EGLDisplay _returnValue = (EGLDisplay) 0;
_returnValue = eglGetDisplay(
- (EGLNativeDisplayType)display_id
+ reinterpret_cast<EGLNativeDisplayType>(display_id)
);
return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
}
+/* EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id ) */
+static jobject
+android_eglGetDisplayInt
+ (JNIEnv *_env, jobject _this, jint display_id) {
+
+ if (sizeof(void*) != sizeof(uint32_t)) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
+ return 0;
+ }
+ return android_eglGetDisplay(_env, _this, display_id);
+}
+
/* EGLBoolean eglInitialize ( EGLDisplay dpy, EGLint *major, EGLint *minor ) */
static jboolean
android_eglInitialize
@@ -852,7 +865,7 @@
/* EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list ) */
static jobject
android_eglCreatePbufferFromClientBuffer
- (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jint buffer, jobject config, jintArray attrib_list_ref, jint offset) {
+ (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jlong buffer, jobject config, jintArray attrib_list_ref, jint offset) {
jint _exception = 0;
const char * _exceptionType = NULL;
const char * _exceptionMessage = NULL;
@@ -897,7 +910,7 @@
_returnValue = eglCreatePbufferFromClientBuffer(
(EGLDisplay)dpy_native,
(EGLenum)buftype,
- (EGLClientBuffer)buffer,
+ reinterpret_cast<EGLClientBuffer>(buffer),
(EGLConfig)config_native,
(EGLint *)attrib_list
);
@@ -913,6 +926,16 @@
return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
}
+static jobject
+android_eglCreatePbufferFromClientBufferInt
+ (JNIEnv *_env, jobject _this, jobject dpy, jint buftype, jint buffer, jobject config, jintArray attrib_list_ref, jint offset) {
+ if(sizeof(void*) != sizeof(uint32_t)) {
+ jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglCreatePbufferFromClientBuffer");
+ return 0;
+ }
+ return android_eglCreatePbufferFromClientBuffer(_env, _this, dpy, buftype, buffer, config, attrib_list_ref, offset);
+}
+
/* EGLBoolean eglSurfaceAttrib ( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value ) */
static jboolean
android_eglSurfaceAttrib
@@ -1207,7 +1230,8 @@
static JNINativeMethod methods[] = {
{"_nativeClassInit", "()V", (void*)nativeClassInit },
{"eglGetError", "()I", (void *) android_eglGetError },
-{"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplay },
+{"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt },
+{"eglGetDisplay", "(J)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplay },
{"eglInitialize", "(Landroid/opengl/EGLDisplay;[II[II)Z", (void *) android_eglInitialize },
{"eglTerminate", "(Landroid/opengl/EGLDisplay;)Z", (void *) android_eglTerminate },
{"eglQueryString", "(Landroid/opengl/EGLDisplay;I)Ljava/lang/String;", (void *) android_eglQueryString__Landroind_opengl_EGLDisplay_2I },
@@ -1224,7 +1248,8 @@
{"eglQueryAPI", "()I", (void *) android_eglQueryAPI },
{"eglWaitClient", "()Z", (void *) android_eglWaitClient },
{"eglReleaseThread", "()Z", (void *) android_eglReleaseThread },
-{"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IILandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBuffer },
+{"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IILandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBufferInt },
+{"eglCreatePbufferFromClientBuffer", "(Landroid/opengl/EGLDisplay;IJLandroid/opengl/EGLConfig;[II)Landroid/opengl/EGLSurface;", (void *) android_eglCreatePbufferFromClientBuffer },
{"eglSurfaceAttrib", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;II)Z", (void *) android_eglSurfaceAttrib },
{"eglBindTexImage", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;I)Z", (void *) android_eglBindTexImage },
{"eglReleaseTexImage", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;I)Z", (void *) android_eglReleaseTexImage },
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 5179ddc..15899f5 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -70,22 +70,22 @@
jclass eglconfigClassLocal = _env->FindClass("android/opengl/EGLConfig");
eglconfigClass = (jclass) _env->NewGlobalRef(eglconfigClassLocal);
- egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getHandle", "()I");
- eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getHandle", "()I");
- eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getHandle", "()I");
- eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getHandle", "()I");
+ egldisplayGetHandleID = _env->GetMethodID(egldisplayClass, "getNativeHandle", "()J");
+ eglcontextGetHandleID = _env->GetMethodID(eglcontextClass, "getNativeHandle", "()J");
+ eglsurfaceGetHandleID = _env->GetMethodID(eglsurfaceClass, "getNativeHandle", "()J");
+ eglconfigGetHandleID = _env->GetMethodID(eglconfigClass, "getNativeHandle", "()J");
- egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(I)V");
- eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(I)V");
- eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(I)V");
- eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(I)V");
+ egldisplayConstructor = _env->GetMethodID(egldisplayClass, "<init>", "(J)V");
+ eglcontextConstructor = _env->GetMethodID(eglcontextClass, "<init>", "(J)V");
+ eglsurfaceConstructor = _env->GetMethodID(eglsurfaceClass, "<init>", "(J)V");
+ eglconfigConstructor = _env->GetMethodID(eglconfigClass, "<init>", "(J)V");
- jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, (jint)EGL_NO_CONTEXT);
+ jobject localeglNoContextObject = _env->NewObject(eglcontextClass, eglcontextConstructor, reinterpret_cast<jlong>(EGL_NO_CONTEXT));
eglNoContextObject = _env->NewGlobalRef(localeglNoContextObject);
- jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, (jint)EGL_NO_DISPLAY);
+ jobject localeglNoDisplayObject = _env->NewObject(egldisplayClass, egldisplayConstructor, reinterpret_cast<jlong>(EGL_NO_DISPLAY));
eglNoDisplayObject = _env->NewGlobalRef(localeglNoDisplayObject);
- jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, (jint)EGL_NO_SURFACE);
+ jobject localeglNoSurfaceObject = _env->NewObject(eglsurfaceClass, eglsurfaceConstructor, reinterpret_cast<jlong>(EGL_NO_SURFACE));
eglNoSurfaceObject = _env->NewGlobalRef(localeglNoSurfaceObject);
@@ -107,7 +107,7 @@
"Object is set to null.");
}
- return (void*) (_env->CallIntMethod(obj, mid));
+ return reinterpret_cast<void*>(_env->CallLongMethod(obj, mid));
}
static jobject
@@ -127,7 +127,7 @@
return eglNoSurfaceObject;
}
- return _env->NewObject(cls, con, (jint)handle);
+ return _env->NewObject(cls, con, reinterpret_cast<jlong>(handle));
}
// --------------------------------------------------------------------------
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index cc34e99..21e19e1 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -111,7 +111,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void*>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 9284384..bc83234 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -111,7 +111,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void*>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 871e84d..a45f269 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -111,7 +111,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void*>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
@@ -578,7 +578,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -679,7 +679,7 @@
(GLenum)mode,
(GLsizei)count,
(GLenum)type,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
@@ -2302,7 +2302,7 @@
glNormalPointer(
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -2529,7 +2529,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -2937,7 +2937,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 3e038ad..05728ef 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -111,7 +111,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void*>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index db03b70..d3e5014 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -111,7 +111,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void*>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
@@ -1180,7 +1180,7 @@
(GLenum)mode,
(GLsizei)count,
(GLenum)type,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
@@ -1804,7 +1804,7 @@
(GLsizei *)length,
(GLint *)size,
(GLenum *)type,
- (char *)name
+ reinterpret_cast<char *>(name)
);
if (_typeArray) {
releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -2132,7 +2132,7 @@
(GLsizei *)length,
(GLint *)size,
(GLenum *)type,
- (char *)name
+ reinterpret_cast<char *>(name)
);
if (_typeArray) {
releasePointer(_env, _typeArray, type, JNI_TRUE);
@@ -3212,7 +3212,7 @@
(GLuint)shader,
(GLsizei)bufsize,
(GLsizei *)length,
- (char *)source
+ reinterpret_cast<char *>(source)
);
if (_array) {
releasePointer(_env, _array, length, JNI_TRUE);
@@ -5985,7 +5985,7 @@
(GLenum)type,
(GLboolean)normalized,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 4c62a75..8821352 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -111,7 +111,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void*>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
@@ -370,7 +370,7 @@
(GLuint)end,
(GLsizei)count,
(GLenum)type,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -419,7 +419,7 @@
(GLint)border,
(GLenum)format,
(GLenum)type,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -470,7 +470,7 @@
(GLsizei)depth,
(GLenum)format,
(GLenum)type,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -534,7 +534,7 @@
(GLsizei)depth,
(GLint)border,
(GLsizei)imageSize,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -585,7 +585,7 @@
(GLsizei)depth,
(GLenum)format,
(GLsizei)imageSize,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -2134,7 +2134,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index db84d000..26405b5 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -415,7 +415,7 @@
return false;
}
- int ret = selinux_android_restorecon(pathname.c_str());
+ int ret = selinux_android_restorecon(pathname.c_str(), 0);
ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
return (ret == 0);
}
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index 5f4d570..62478442 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -19,13 +19,6 @@
* System clock functions.
*/
-#ifdef HAVE_ANDROID_OS
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <utils/Atomic.h>
-#include <linux/android_alarm.h>
-#endif
-
#include <sys/time.h>
#include <limits.h>
#include <fcntl.h>
@@ -43,109 +36,6 @@
namespace android {
-static int setCurrentTimeMillisAlarmDriver(struct timeval *tv)
-{
- struct timespec ts;
- int fd;
- int res;
-
- fd = open("/dev/alarm", O_RDWR);
- if(fd < 0) {
- ALOGV("Unable to open alarm driver: %s\n", strerror(errno));
- return -1;
- }
- ts.tv_sec = tv->tv_sec;
- ts.tv_nsec = tv->tv_usec * 1000;
- res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts);
- if (res < 0)
- ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
- close(fd);
- return res;
-}
-
-static int setCurrentTimeMillisRtc(struct timeval *tv)
-{
- struct rtc_time rtc;
- struct tm tm, *gmtime_res;
- int fd;
- int res;
-
- fd = open("/dev/rtc0", O_RDWR);
- if (fd < 0) {
- ALOGV("Unable to open RTC driver: %s\n", strerror(errno));
- return -1;
- }
-
- res = settimeofday(tv, NULL);
- if (res < 0) {
- ALOGV("settimeofday() failed: %s\n", strerror(errno));
- goto done;
- }
-
- gmtime_res = gmtime_r(&tv->tv_sec, &tm);
- if (!gmtime_res) {
- ALOGV("gmtime_r() failed: %s\n", strerror(errno));
- res = -1;
- goto done;
- }
-
- memset(&rtc, 0, sizeof(rtc));
- rtc.tm_sec = tm.tm_sec;
- rtc.tm_min = tm.tm_min;
- rtc.tm_hour = tm.tm_hour;
- rtc.tm_mday = tm.tm_mday;
- rtc.tm_mon = tm.tm_mon;
- rtc.tm_year = tm.tm_year;
- rtc.tm_wday = tm.tm_wday;
- rtc.tm_yday = tm.tm_yday;
- rtc.tm_isdst = tm.tm_isdst;
- res = ioctl(fd, RTC_SET_TIME, &rtc);
- if (res < 0)
- ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
-done:
- close(fd);
- return res;
-}
-
-/*
- * Set the current time. This only works when running as root.
- */
-static int setCurrentTimeMillis(int64_t millis)
-{
- struct timeval tv;
- int ret;
-
- if (millis <= 0 || millis / 1000LL >= INT_MAX) {
- return -1;
- }
-
- tv.tv_sec = (time_t) (millis / 1000LL);
- tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
-
- ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
-
- ret = setCurrentTimeMillisAlarmDriver(&tv);
- if (ret < 0)
- ret = setCurrentTimeMillisRtc(&tv);
-
- if(ret < 0) {
- ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
- ret = -1;
- }
- return ret;
-}
-
-/*
- * native public static void setCurrentTimeMillis(long millis)
- *
- * Set the current time. This only works when running as root.
- */
-static jboolean android_os_SystemClock_setCurrentTimeMillis(JNIEnv* env,
- jobject clazz, jlong millis)
-{
- return (setCurrentTimeMillis(millis) == 0);
-}
-
/*
* native public static long uptimeMillis();
*/
@@ -230,8 +120,6 @@
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "setCurrentTimeMillis", "(J)Z",
- (void*) android_os_SystemClock_setCurrentTimeMillis },
{ "uptimeMillis", "()J",
(void*) android_os_SystemClock_uptimeMillis },
{ "elapsedRealtime", "()J",
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index f96aef8..7162a1c 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -35,7 +35,16 @@
#include <androidfw/AssetManager.h>
#include <androidfw/ResourceTypes.h>
+#include <private/android_filesystem_config.h> // for AID_SYSTEM
+
#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <linux/capability.h>
+extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
+extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+
namespace android {
@@ -100,6 +109,63 @@
return block;
}
+// This is called by zygote (running as user root) as part of preloadResources.
+static void verifySystemIdmaps()
+{
+ pid_t pid;
+ char system_id[10];
+
+ snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
+
+ switch (pid = fork()) {
+ case -1:
+ ALOGE("failed to fork for idmap: %s", strerror(errno));
+ break;
+ case 0: // child
+ {
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata;
+
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+
+ capheader.version = _LINUX_CAPABILITY_VERSION;
+ capheader.pid = 0;
+
+ if (capget(&capheader, &capdata) != 0) {
+ ALOGE("capget: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ capdata.effective = capdata.permitted;
+ if (capset(&capheader, &capdata) != 0) {
+ ALOGE("capset: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (setgid(AID_SYSTEM) != 0) {
+ ALOGE("setgid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if (setuid(AID_SYSTEM) != 0) {
+ ALOGE("setuid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan",
+ AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME,
+ AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL);
+ ALOGE("failed to execl for idmap: %s", strerror(errno));
+ exit(1); // should never get here
+ }
+ break;
+ default: // parent
+ waitpid(pid, NULL, 0);
+ break;
+ }
+}
+
// ----------------------------------------------------------------------------
// this guy is exported to other jni routines
@@ -444,6 +510,25 @@
return (res) ? static_cast<jint>(cookie) : 0;
}
+static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
+ jstring idmapPath)
+{
+ ScopedUtfChars idmapPath8(env, idmapPath);
+ if (idmapPath8.c_str() == NULL) {
+ return 0;
+ }
+
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return 0;
+ }
+
+ int32_t cookie;
+ bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
+
+ return (res) ? (jint)cookie : 0;
+}
+
static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
@@ -1579,8 +1664,11 @@
return array;
}
-static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
+static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
{
+ if (isSystem) {
+ verifySystemIdmaps();
+ }
AssetManager* am = new AssetManager();
if (am == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", "");
@@ -1658,6 +1746,8 @@
(void*) android_content_AssetManager_getAssetRemainingLength },
{ "addAssetPathNative", "(Ljava/lang/String;)I",
(void*) android_content_AssetManager_addAssetPath },
+ { "addOverlayPath", "(Ljava/lang/String;)I",
+ (void*) android_content_AssetManager_addOverlayPath },
{ "isUpToDate", "()Z",
(void*) android_content_AssetManager_isUpToDate },
@@ -1724,7 +1814,7 @@
(void*) android_content_AssetManager_getArrayIntResource },
// Bookkeeping.
- { "init", "()V",
+ { "init", "(Z)V",
(void*) android_content_AssetManager_init },
{ "destroy", "()V",
(void*) android_content_AssetManager_destroy },
diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp
index de68b97..e47e23c 100644
--- a/core/jni/android_view_DisplayList.cpp
+++ b/core/jni/android_view_DisplayList.cpp
@@ -142,10 +142,10 @@
displayList->setCastsShadow(castsShadow);
}
-static void android_view_DisplayList_setSharesGlobalCamera(JNIEnv* env,
- jobject clazz, jlong displayListPtr, jboolean sharesGlobalCamera) {
+static void android_view_DisplayList_setUsesGlobalCamera(JNIEnv* env,
+ jobject clazz, jlong displayListPtr, jboolean usesGlobalCamera) {
DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
- displayList->setSharesGlobalCamera(sharesGlobalCamera);
+ displayList->setUsesGlobalCamera(usesGlobalCamera);
}
static void android_view_DisplayList_setAlpha(JNIEnv* env,
@@ -420,7 +420,7 @@
{ "nSetOutline", "(JJ)V", (void*) android_view_DisplayList_setOutline },
{ "nSetClipToOutline", "(JZ)V", (void*) android_view_DisplayList_setClipToOutline },
{ "nSetCastsShadow", "(JZ)V", (void*) android_view_DisplayList_setCastsShadow },
- { "nSetSharesGlobalCamera","(JZ)V", (void*) android_view_DisplayList_setSharesGlobalCamera },
+ { "nSetUsesGlobalCamera", "(JZ)V", (void*) android_view_DisplayList_setUsesGlobalCamera },
{ "nSetAlpha", "(JF)V", (void*) android_view_DisplayList_setAlpha },
{ "nSetHasOverlappingRendering", "(JZ)V",
(void*) android_view_DisplayList_setHasOverlappingRendering },
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index dd089f2..4e353fa 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -116,14 +116,12 @@
// ----------------------------------------------------------------------------
static void android_view_GLES20Canvas_initAtlas(JNIEnv* env, jobject clazz,
- jobject graphicBuffer, jintArray atlasMapArray, jint count) {
+ jobject graphicBuffer, jlongArray atlasMapArray, jint count) {
sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
- jint* atlasMap = env->GetIntArrayElements(atlasMapArray, NULL);
-
- Caches::getInstance().assetAtlas.init(buffer, atlasMap, count);
-
- env->ReleaseIntArrayElements(atlasMapArray, atlasMap, 0);
+ jlong* jAtlasMap = env->GetLongArrayElements(atlasMapArray, NULL);
+ Caches::getInstance().assetAtlas.init(buffer, jAtlasMap, count);
+ env->ReleaseLongArrayElements(atlasMapArray, jAtlasMap, 0);
}
// ----------------------------------------------------------------------------
@@ -1002,7 +1000,7 @@
{ "nInitCaches", "()Z", (void*) android_view_GLES20Canvas_initCaches },
{ "nTerminateCaches", "()V", (void*) android_view_GLES20Canvas_terminateCaches },
- { "nInitAtlas", "(Landroid/view/GraphicBuffer;[II)V",
+ { "nInitAtlas", "(Landroid/view/GraphicBuffer;[JI)V",
(void*) android_view_GLES20Canvas_initAtlas },
{ "nCreateRenderer", "()J", (void*) android_view_GLES20Canvas_createRenderer },
diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp
index 7cf93d0..5c5b52c 100644
--- a/core/jni/android_view_GLRenderer.cpp
+++ b/core/jni/android_view_GLRenderer.cpp
@@ -28,6 +28,7 @@
#include <Caches.h>
#include <Extensions.h>
+#include <LayerRenderer.h>
#ifdef USE_OPENGL_RENDERER
EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
@@ -131,6 +132,13 @@
return systemTime(SYSTEM_TIME_MONOTONIC);
}
+static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz,
+ jlong layerPtr) {
+ using namespace android::uirenderer;
+ Layer* layer = reinterpret_cast<Layer*>(layerPtr);
+ LayerRenderer::destroyLayer(layer);
+}
+
#endif // USE_OPENGL_RENDERER
// ----------------------------------------------------------------------------
@@ -160,6 +168,7 @@
{ "beginFrame", "([I)V", (void*) android_view_GLRenderer_beginFrame },
{ "getSystemTime", "()J", (void*) android_view_GLRenderer_getSystemTime },
+ { "nDestroyLayer", "(J)V", (void*) android_view_GLRenderer_destroyLayer },
#endif
{ "setupShadersDiskCache", "(Ljava/lang/String;)V",
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 8a0a011..5b21e94 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -88,13 +88,11 @@
}
static void android_view_HardwareLayer_setLayerPaint(JNIEnv* env, jobject clazz,
- jlong layerUpdaterPtr, jlong paintPtr, jlong colorFilterPtr) {
+ jlong layerUpdaterPtr, jlong paintPtr) {
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
if (layer) {
SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
- SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
layer->setPaint(paint);
- layer->setColorFilter(colorFilter);
}
}
@@ -162,7 +160,7 @@
{ "nDestroyLayerUpdater", "(J)V", (void*) android_view_HardwareLayer_destroyLayerUpdater },
{ "nPrepare", "(JIIZ)Z", (void*) android_view_HardwareLayer_prepare },
- { "nSetLayerPaint", "(JJJ)V", (void*) android_view_HardwareLayer_setLayerPaint },
+ { "nSetLayerPaint", "(JJ)V", (void*) android_view_HardwareLayer_setLayerPaint },
{ "nSetTransform", "(JJ)V", (void*) android_view_HardwareLayer_setTransform },
{ "nSetSurfaceTexture", "(JLandroid/graphics/SurfaceTexture;Z)V",
(void*) android_view_HardwareLayer_setSurfaceTexture },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 88ec0d7..c5ab284 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -61,51 +61,21 @@
class ScreenshotPixelRef : public SkPixelRef {
public:
- ScreenshotPixelRef(SkColorTable* ctable) {
- fCTable = ctable;
- SkSafeRef(ctable);
+ ScreenshotPixelRef(const SkImageInfo& info, ScreenshotClient* screenshot) :
+ SkPixelRef(info),
+ mScreenshot(screenshot) {
setImmutable();
}
virtual ~ScreenshotPixelRef() {
- SkSafeUnref(fCTable);
- }
-
- status_t update(const sp<IBinder>& display, int width, int height,
- int minLayer, int maxLayer, bool allLayers) {
- status_t res = (width > 0 && height > 0)
- ? (allLayers
- ? mScreenshot.update(display, width, height)
- : mScreenshot.update(display, width, height, minLayer, maxLayer))
- : mScreenshot.update(display);
- if (res != NO_ERROR) {
- return res;
- }
-
- return NO_ERROR;
- }
-
- uint32_t getWidth() const {
- return mScreenshot.getWidth();
- }
-
- uint32_t getHeight() const {
- return mScreenshot.getHeight();
- }
-
- uint32_t getStride() const {
- return mScreenshot.getStride();
- }
-
- uint32_t getFormat() const {
- return mScreenshot.getFormat();
+ delete mScreenshot;
}
protected:
// overrides from SkPixelRef
virtual void* onLockPixels(SkColorTable** ct) {
- *ct = fCTable;
- return (void*)mScreenshot.getPixels();
+ *ct = NULL;
+ return (void*)mScreenshot->getPixels();
}
virtual void onUnlockPixels() {
@@ -113,8 +83,7 @@
SK_DECLARE_UNFLATTENABLE_OBJECT()
private:
- ScreenshotClient mScreenshot;
- SkColorTable* fCTable;
+ ScreenshotClient* mScreenshot;
typedef SkPixelRef INHERITED;
};
@@ -147,47 +116,65 @@
ctrl->decStrong((void *)nativeCreate);
}
-static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
- /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
- we can map to SkBitmap::kARGB_8888_Config, and optionally call
- bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
- (as an accelerator)
- */
- switch (format) {
- case PIXEL_FORMAT_RGBX_8888: return SkBitmap::kARGB_8888_Config;
- case PIXEL_FORMAT_RGBA_8888: return SkBitmap::kARGB_8888_Config;
- case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config;
- default: return SkBitmap::kNo_Config;
- }
-}
-
static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj,
- jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
+ jint width, jint height, jint minLayer, jint maxLayer, bool allLayers,
+ bool useIdentityTransform) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken == NULL) {
return NULL;
}
- ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
- if (pixels->update(displayToken, width, height,
- minLayer, maxLayer, allLayers) != NO_ERROR) {
- delete pixels;
+ ScreenshotClient* screenshot = new ScreenshotClient();
+ status_t res;
+ if (width > 0 && height > 0) {
+ if (allLayers) {
+ res = screenshot->update(displayToken, width, height, useIdentityTransform);
+ } else {
+ res = screenshot->update(displayToken, width, height, minLayer, maxLayer,
+ useIdentityTransform);
+ }
+ } else {
+ res = screenshot->update(displayToken, useIdentityTransform);
+ }
+ if (res != NO_ERROR) {
+ delete screenshot;
return NULL;
}
- uint32_t w = pixels->getWidth();
- uint32_t h = pixels->getHeight();
- uint32_t s = pixels->getStride();
- uint32_t f = pixels->getFormat();
- ssize_t bpr = s * android::bytesPerPixel(f);
+ SkImageInfo screenshotInfo;
+ screenshotInfo.fWidth = screenshot->getWidth();
+ screenshotInfo.fHeight = screenshot->getHeight();
- SkBitmap* bitmap = new SkBitmap();
- bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
- if (f == PIXEL_FORMAT_RGBX_8888) {
- bitmap->setAlphaType(kOpaque_SkAlphaType);
+ switch (screenshot->getFormat()) {
+ case PIXEL_FORMAT_RGBX_8888: {
+ screenshotInfo.fColorType = kRGBA_8888_SkColorType;
+ screenshotInfo.fAlphaType = kIgnore_SkAlphaType;
+ break;
+ }
+ case PIXEL_FORMAT_RGBA_8888: {
+ screenshotInfo.fColorType = kRGBA_8888_SkColorType;
+ screenshotInfo.fAlphaType = kPremul_SkAlphaType;
+ break;
+ }
+ case PIXEL_FORMAT_RGB_565: {
+ screenshotInfo.fColorType = kRGB_565_SkColorType;
+ screenshotInfo.fAlphaType = kIgnore_SkAlphaType;
+ break;
+ }
+ default: {
+ delete screenshot;
+ return NULL;
+ }
}
- if (w > 0 && h > 0) {
+ // takes ownership of ScreenshotClient
+ ScreenshotPixelRef* pixels = new ScreenshotPixelRef(screenshotInfo, screenshot);
+ const ssize_t rowBytes =
+ screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
+
+ SkBitmap* bitmap = new SkBitmap();
+ bitmap->setConfig(screenshotInfo, (size_t)rowBytes);
+ if (screenshotInfo.fWidth > 0 && screenshotInfo.fHeight > 0) {
bitmap->setPixelRef(pixels)->unref();
bitmap->lockPixels();
} else {
@@ -202,7 +189,8 @@
static void nativeScreenshot(JNIEnv* env, jclass clazz,
jobject displayTokenObj, jobject surfaceObj,
- jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
+ jint width, jint height, jint minLayer, jint maxLayer, bool allLayers,
+ bool useIdentityTransform) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken != NULL) {
sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
@@ -213,7 +201,8 @@
}
ScreenshotClient::capture(
displayToken, consumer->getIGraphicBufferProducer(),
- width, height, uint32_t(minLayer), uint32_t(maxLayer));
+ width, height, uint32_t(minLayer), uint32_t(maxLayer),
+ useIdentityTransform);
}
}
}
@@ -417,9 +406,9 @@
(void*)nativeRelease },
{"nativeDestroy", "(J)V",
(void*)nativeDestroy },
- {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
+ {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZZ)Landroid/graphics/Bitmap;",
(void*)nativeScreenshotBitmap },
- {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZ)V",
+ {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZZ)V",
(void*)nativeScreenshot },
{"nativeOpenTransaction", "()V",
(void*)nativeOpenTransaction },
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 87e339c..609c565 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -35,22 +35,22 @@
sp<SurfaceComposerClient> android_view_SurfaceSession_getClient(
JNIEnv* env, jobject surfaceSessionObj) {
return reinterpret_cast<SurfaceComposerClient*>(
- env->GetIntField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
+ env->GetLongField(surfaceSessionObj, gSurfaceSessionClassInfo.mNativeClient));
}
-static jint nativeCreate(JNIEnv* env, jclass clazz) {
+static jlong nativeCreate(JNIEnv* env, jclass clazz) {
SurfaceComposerClient* client = new SurfaceComposerClient();
client->incStrong((void*)nativeCreate);
- return reinterpret_cast<jint>(client);
+ return reinterpret_cast<jlong>(client);
}
-static void nativeDestroy(JNIEnv* env, jclass clazz, jint ptr) {
+static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
client->decStrong((void*)nativeCreate);
}
-static void nativeKill(JNIEnv* env, jclass clazz, jint ptr) {
+static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) {
SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
client->dispose();
}
@@ -58,11 +58,11 @@
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "nativeCreate", "()I",
+ { "nativeCreate", "()J",
(void*)nativeCreate },
- { "nativeDestroy", "(I)V",
+ { "nativeDestroy", "(J)V",
(void*)nativeDestroy },
- { "nativeKill", "(I)V",
+ { "nativeKill", "(J)V",
(void*)nativeKill }
};
@@ -72,7 +72,7 @@
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
jclass clazz = env->FindClass("android/view/SurfaceSession");
- gSurfaceSessionClassInfo.mNativeClient = env->GetFieldID(clazz, "mNativeClient", "I");
+ gSurfaceSessionClassInfo.mNativeClient = env->GetFieldID(clazz, "mNativeClient", "J");
return 0;
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index e86a2d4..bc5c06e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -76,20 +76,20 @@
static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
delete proxy;
}
static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
return proxy->initialize(window.get());
}
static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jsurface) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
sp<ANativeWindow> window;
if (jsurface) {
window = android_view_Surface_getNativeWindow(env, jsurface);
@@ -99,45 +99,74 @@
static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
jlong proxyPtr, jint width, jint height) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->setup(width, height);
}
static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
jint dirtyRight, jint dirtyBottom) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
- DisplayList* displayList = reinterpret_cast<DisplayList*>( displayListPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
}
static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject clazz,
jlong proxyPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->destroyCanvas();
}
static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong functorPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
proxy->attachFunctor(functor);
}
static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlong functorPtr) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
Functor* functor = reinterpret_cast<Functor*>(functorPtr);
proxy->detachFunctor(functor);
}
static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
jlong proxyPtr, jobject jrunnable) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
RenderTask* task = new JavaTask(env, jrunnable);
proxy->runWithGlContext(task);
}
+static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jint width, jint height) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
+ return reinterpret_cast<jlong>(layer);
+}
+
+static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = proxy->createTextureLayer();
+ return reinterpret_cast<jlong>(layer);
+}
+
+static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+ return proxy->copyLayerInto(layer, bitmap);
+}
+
+static void android_view_ThreadedRenderer_destroyLayer(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jlong layerPtr) {
+ RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+ proxy->destroyLayer(layer);
+}
+
#endif
// ----------------------------------------------------------------------------
@@ -159,6 +188,10 @@
{ "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor},
{ "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor},
{ "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
+ { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
+ { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
+ { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+ { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
#endif
};
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 0b9ad9b..c84a466 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -37,6 +37,7 @@
static struct {
jfieldID size;
+ jfieldID capacity;
jfieldID iface;
jfieldID uid;
jfieldID set;
@@ -49,7 +50,6 @@
} gNetworkStatsClassInfo;
struct stats_line {
- int32_t idx;
char iface[32];
int32_t uid;
int32_t set;
@@ -60,8 +60,41 @@
int64_t txPackets;
};
+static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
+{
+ if (!grow) {
+ jobjectArray array = (jobjectArray)env->GetObjectField(obj, field);
+ if (array != NULL) {
+ return array;
+ }
+ }
+ return env->NewObjectArray(size, gStringClass, NULL);
+}
+
+static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
+{
+ if (!grow) {
+ jintArray array = (jintArray)env->GetObjectField(obj, field);
+ if (array != NULL) {
+ return array;
+ }
+ }
+ return env->NewIntArray(size);
+}
+
+static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow)
+{
+ if (!grow) {
+ jlongArray array = (jlongArray)env->GetObjectField(obj, field);
+ if (array != NULL) {
+ return array;
+ }
+ }
+ return env->NewLongArray(size);
+}
+
static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats,
- jstring path, jint limitUid) {
+ jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag) {
ScopedUtfChars path8(env, path);
if (path8.c_str() == NULL) {
return -1;
@@ -72,50 +105,146 @@
return -1;
}
+ Vector<String8> limitIfaces;
+ if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
+ int num = env->GetArrayLength(limitIfacesObj);
+ limitIfaces.setCapacity(num);
+ for (int i=0; i<num; i++) {
+ jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
+ ScopedUtfChars string8(env, string);
+ if (string8.c_str() != NULL) {
+ limitIfaces.add(String8(string8.c_str()));
+ }
+ }
+ }
+
Vector<stats_line> lines;
int lastIdx = 1;
+ int idx;
char buffer[384];
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
stats_line s;
int64_t rawTag;
- if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx,
- s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
- &s.txBytes, &s.txPackets) == 9) {
- if (s.idx != lastIdx + 1) {
- ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx);
- return -1;
+ char* pos = buffer;
+ char* endPos;
+ // First field is the index.
+ idx = (int)strtol(pos, &endPos, 10);
+ //ALOGI("Index #%d: %s", idx, buffer);
+ if (pos == endPos) {
+ // Skip lines that don't start with in index. In particular,
+ // this will skip the initial header line.
+ continue;
+ }
+ if (idx != lastIdx + 1) {
+ ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer);
+ fclose(fp);
+ return -1;
+ }
+ lastIdx = idx;
+ pos = endPos;
+ // Skip whitespace.
+ while (*pos == ' ') {
+ pos++;
+ }
+ // Next field is iface.
+ int ifaceIdx = 0;
+ while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) {
+ s.iface[ifaceIdx] = *pos;
+ ifaceIdx++;
+ pos++;
+ }
+ if (*pos != ' ') {
+ ALOGE("bad iface: %s", buffer);
+ fclose(fp);
+ return -1;
+ }
+ s.iface[ifaceIdx] = 0;
+ if (limitIfaces.size() > 0) {
+ // Is this an iface the caller is interested in?
+ int i = 0;
+ while (i < (int)limitIfaces.size()) {
+ if (limitIfaces[i] == s.iface) {
+ break;
+ }
+ i++;
}
- lastIdx = s.idx;
-
- s.tag = rawTag >> 32;
+ if (i >= (int)limitIfaces.size()) {
+ // Nothing matched; skip this line.
+ //ALOGI("skipping due to iface: %s", buffer);
+ continue;
+ }
+ }
+ // Skip whitespace.
+ while (*pos == ' ') {
+ pos++;
+ }
+ // Next field is tag.
+ rawTag = strtoll(pos, &endPos, 16);
+ //ALOGI("Index #%d: %s", idx, buffer);
+ if (pos == endPos) {
+ ALOGE("bad tag: %s", pos);
+ fclose(fp);
+ return -1;
+ }
+ s.tag = rawTag >> 32;
+ if (limitTag != -1 && s.tag != limitTag) {
+ //ALOGI("skipping due to tag: %s", buffer);
+ continue;
+ }
+ pos = endPos;
+ // Skip whitespace.
+ while (*pos == ' ') {
+ pos++;
+ }
+ // Parse remaining fields.
+ if (sscanf(pos, "%u %u %llu %llu %llu %llu",
+ &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
+ &s.txBytes, &s.txPackets) == 6) {
+ if (limitUid != -1 && limitUid != s.uid) {
+ //ALOGI("skipping due to uid: %s", buffer);
+ continue;
+ }
lines.push_back(s);
+ } else {
+ //ALOGI("skipping due to bad remaining fields: %s", pos);
}
}
if (fclose(fp) != 0) {
+ ALOGE("Failed to close netstats file");
return -1;
}
int size = lines.size();
+ bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity);
- ScopedLocalRef<jobjectArray> iface(env, env->NewObjectArray(size, gStringClass, NULL));
+ ScopedLocalRef<jobjectArray> iface(env, get_string_array(env, stats,
+ gNetworkStatsClassInfo.iface, size, grow));
if (iface.get() == NULL) return -1;
- ScopedIntArrayRW uid(env, env->NewIntArray(size));
+ ScopedIntArrayRW uid(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.uid, size, grow));
if (uid.get() == NULL) return -1;
- ScopedIntArrayRW set(env, env->NewIntArray(size));
+ ScopedIntArrayRW set(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.set, size, grow));
if (set.get() == NULL) return -1;
- ScopedIntArrayRW tag(env, env->NewIntArray(size));
+ ScopedIntArrayRW tag(env, get_int_array(env, stats,
+ gNetworkStatsClassInfo.tag, size, grow));
if (tag.get() == NULL) return -1;
- ScopedLongArrayRW rxBytes(env, env->NewLongArray(size));
+ ScopedLongArrayRW rxBytes(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.rxBytes, size, grow));
if (rxBytes.get() == NULL) return -1;
- ScopedLongArrayRW rxPackets(env, env->NewLongArray(size));
+ ScopedLongArrayRW rxPackets(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.rxPackets, size, grow));
if (rxPackets.get() == NULL) return -1;
- ScopedLongArrayRW txBytes(env, env->NewLongArray(size));
+ ScopedLongArrayRW txBytes(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.txBytes, size, grow));
if (txBytes.get() == NULL) return -1;
- ScopedLongArrayRW txPackets(env, env->NewLongArray(size));
+ ScopedLongArrayRW txPackets(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.txPackets, size, grow));
if (txPackets.get() == NULL) return -1;
- ScopedLongArrayRW operations(env, env->NewLongArray(size));
+ ScopedLongArrayRW operations(env, get_long_array(env, stats,
+ gNetworkStatsClassInfo.operations, size, grow));
if (operations.get() == NULL) return -1;
for (int i = 0; i < size; i++) {
@@ -132,15 +261,18 @@
}
env->SetIntField(stats, gNetworkStatsClassInfo.size, size);
- env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get());
- env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
- env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
+ if (grow) {
+ env->SetIntField(stats, gNetworkStatsClassInfo.capacity, size);
+ env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray());
+ env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray());
+ }
return 0;
}
@@ -157,7 +289,7 @@
static JNINativeMethod gMethods[] = {
{ "nativeReadNetworkStatsDetail",
- "(Landroid/net/NetworkStats;Ljava/lang/String;I)I",
+ "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
(void*) readNetworkStatsDetail }
};
@@ -170,6 +302,7 @@
jclass clazz = env->FindClass("android/net/NetworkStats");
gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
+ gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I");
gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;");
gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I");
gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I");
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index b3b0049..7975987 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -129,7 +129,7 @@
getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
- return (void *) (jint) pointer;
+ return reinterpret_cast<void *>(pointer);
}
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
@@ -4359,7 +4359,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -4460,7 +4460,7 @@
(GLenum)mode,
(GLsizei)count,
(GLenum)type,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
if (_exception) {
jniThrowException(_env, _exceptionType, _exceptionMessage);
@@ -6099,7 +6099,7 @@
glNormalPointer(
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -6326,7 +6326,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -6756,7 +6756,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -7196,7 +7196,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
@@ -7232,7 +7232,7 @@
(GLint)size,
(GLenum)type,
(GLsizei)stride,
- (GLvoid *)offset
+ reinterpret_cast<GLvoid *>(offset)
);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7ea08af..30e6161 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1103,6 +1103,14 @@
android:label="@string/permlab_readPhoneState"
android:description="@string/permdesc_readPhoneState" />
+ <!-- Allows read only access to precise phone state.
+ @hide Pending API council approval -->
+ <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
+ android:permissionGroup="android.permission-group.PHONE_CALLS"
+ android:protectionLevel="dangerous"
+ android:label="@string/permlab_readPrecisePhoneState"
+ android:description="@string/permdesc_readPrecisePhoneState" />
+
<!-- Allows read access to privileged phone state.
@hide Used internally. -->
<permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
@@ -1206,7 +1214,7 @@
android:permissionGroup="android.permission-group.STORAGE"
android:label="@string/permlab_manageDocs"
android:description="@string/permdesc_manageDocs"
- android:protectionLevel="signature|system" />
+ android:protectionLevel="signature" />
<!-- ================================== -->
<!-- Permissions for screenlock -->
@@ -1541,7 +1549,7 @@
@hide -->
<permission android:name="android.permission.FORCE_STOP_PACKAGES"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
- android:protectionLevel="signature"
+ android:protectionLevel="signature|system"
android:label="@string/permlab_forceStopPackages"
android:description="@string/permdesc_forceStopPackages" />
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/primary_text_disable_only_quantum_dark.xml
similarity index 69%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/primary_text_disable_only_quantum_dark.xml
index 4e88855..2a6c33c 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/primary_text_disable_only_quantum_dark.xml
@@ -14,10 +14,7 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@android:color/bright_foreground_dark_disabled"/>
+ <item android:color="@android:color/bright_foreground_dark"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/primary_text_disable_only_quantum_light.xml
similarity index 69%
rename from packages/SystemUI/res/anim/notification_dnd_off.xml
rename to core/res/res/color/primary_text_disable_only_quantum_light.xml
index 4e88855..ff83f6a 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/primary_text_disable_only_quantum_light.xml
@@ -14,10 +14,7 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@android:color/bright_foreground_light_disabled"/>
+ <item android:color="@android:color/bright_foreground_light"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/primary_text_nodisable_quantum_dark.xml
similarity index 64%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/primary_text_nodisable_quantum_dark.xml
index 4e88855..1044428 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/primary_text_nodisable_quantum_dark.xml
@@ -14,10 +14,8 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="@android:color/bright_foreground_dark_inverse"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/>
+ <item android:color="@android:color/bright_foreground_dark"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/primary_text_nodisable_quantum_light.xml
similarity index 65%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/primary_text_nodisable_quantum_light.xml
index 4e88855..fde143f 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/primary_text_nodisable_quantum_light.xml
@@ -14,10 +14,8 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="@android:color/bright_foreground_light"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_light"/>
+ <item android:color="@android:color/bright_foreground_light"/>
+</selector>
diff --git a/core/res/res/color/primary_text_quantum_dark.xml b/core/res/res/color/primary_text_quantum_dark.xml
new file mode 100644
index 0000000..65f49ae
--- /dev/null
+++ b/core/res/res/color/primary_text_quantum_dark.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@android:color/bright_foreground_disabled_holo_dark"/>
+ <item android:state_window_focused="false" android:color="@android:color/bright_foreground_holo_dark"/>
+ <item android:state_pressed="true" android:color="@android:color/bright_foreground_holo_dark"/>
+ <item android:state_selected="true" android:color="@android:color/bright_foreground_holo_dark"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_dark"/>
+ <item android:color="@android:color/bright_foreground_holo_dark"/>
+</selector>
diff --git a/core/res/res/color/primary_text_quantum_light.xml b/core/res/res/color/primary_text_quantum_light.xml
new file mode 100644
index 0000000..372745d
--- /dev/null
+++ b/core/res/res/color/primary_text_quantum_light.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="@android:color/bright_foreground_disabled_holo_light"/>
+ <item android:state_window_focused="false" android:color="@android:color/bright_foreground_holo_light"/>
+ <item android:state_pressed="true" android:color="@android:color/bright_foreground_holo_light"/>
+ <item android:state_selected="true" android:color="@android:color/bright_foreground_holo_light"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_light"/>
+ <item android:color="@android:color/bright_foreground_holo_light"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/search_url_text_quantum_dark.xml
similarity index 65%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/search_url_text_quantum_dark.xml
index 4e88855..62337bd 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/search_url_text_quantum_dark.xml
@@ -14,10 +14,8 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@android:color/search_url_text_pressed"/>
+ <item android:state_selected="true" android:color="@android:color/search_url_text_selected"/>
+ <item android:color="@android:color/search_url_text_normal"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/search_url_text_quantum_light.xml
similarity index 65%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/search_url_text_quantum_light.xml
index 4e88855..62337bd 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/search_url_text_quantum_light.xml
@@ -14,10 +14,8 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:color="@android:color/search_url_text_pressed"/>
+ <item android:state_selected="true" android:color="@android:color/search_url_text_selected"/>
+ <item android:color="@android:color/search_url_text_normal"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/secondary_text_nodisable_quantum_dark.xml
similarity index 65%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/secondary_text_nodisable_quantum_dark.xml
index 4e88855..3ab25a0 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/secondary_text_nodisable_quantum_dark.xml
@@ -14,10 +14,8 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/>
+ <item android:color="@android:color/dim_foreground_dark"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/secondary_text_nodisable_quantum_light.xml
similarity index 65%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/secondary_text_nodisable_quantum_light.xml
index 4e88855..3ab25a0 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/secondary_text_nodisable_quantum_light.xml
@@ -14,10 +14,8 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_selected="true" android:color="@android:color/dim_foreground_dark_inverse"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_dark_inverse"/>
+ <item android:color="@android:color/dim_foreground_dark"/>
+</selector>
diff --git a/core/res/res/color/secondary_text_quantum_dark.xml b/core/res/res/color/secondary_text_quantum_dark.xml
new file mode 100644
index 0000000..fb7a07a
--- /dev/null
+++ b/core/res/res/color/secondary_text_quantum_dark.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+ <item android:state_window_focused="false" android:color="@android:color/dim_foreground_holo_dark"/>
+ <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+ <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+ <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_dark"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_dark"/>
+ <item android:state_pressed="true" android:color="@android:color/dim_foreground_holo_dark"/>
+ <item android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_dark"/>
+ <item android:color="@android:color/dim_foreground_holo_dark"/>
+</selector>
diff --git a/core/res/res/color/secondary_text_quantum_light.xml b/core/res/res/color/secondary_text_quantum_light.xml
new file mode 100644
index 0000000..744ace5
--- /dev/null
+++ b/core/res/res/color/secondary_text_quantum_light.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/>
+ <item android:state_window_focused="false" android:color="@android:color/dim_foreground_holo_light"/>
+ <!-- Since there is only one selector (for both light and dark), the light's selected state shouldn't be inversed like the dark's. -->
+ <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/>
+ <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/>
+ <item android:state_pressed="true" android:color="@android:color/dim_foreground_holo_light"/>
+ <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_light"/>
+ <item android:state_activated="true" android:color="@android:color/bright_foreground_holo_light"/>
+ <item android:state_enabled="false" android:color="@android:color/dim_foreground_disabled_holo_light"/>
+ <item android:color="@android:color/dim_foreground_holo_light"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/lights_out_in.xml b/core/res/res/color/tertiary_text_quantum_dark.xml
similarity index 60%
rename from packages/SystemUI/res/anim/lights_out_in.xml
rename to core/res/res/color/tertiary_text_quantum_dark.xml
index f76a452..cb39565 100644
--- a/packages/SystemUI/res/anim/lights_out_in.xml
+++ b/core/res/res/color/tertiary_text_quantum_dark.xml
@@ -14,13 +14,10 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromYDelta="-100%p" android:toYDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
- <alpha android:fromAlpha="0.5" android:toAlpha="1.0"
- android:duration="@android:integer/config_longAnimTime"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="#808080"/>
+ <item android:state_window_focused="false" android:color="#808080"/>
+ <item android:state_pressed="true" android:color="#808080"/>
+ <item android:state_selected="true" android:color="@android:color/dim_foreground_holo_light"/>
+ <item android:color="#808080"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/color/tertiary_text_quantum_light.xml
similarity index 62%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/color/tertiary_text_quantum_light.xml
index 4e88855..b23162a 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/color/tertiary_text_quantum_light.xml
@@ -14,10 +14,10 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:color="#808080"/>
+ <item android:state_window_focused="false" android:color="#808080"/>
+ <item android:state_pressed="true" android:color="#808080"/>
+ <item android:state_selected="true" android:color="#808080"/>
+ <item android:color="#808080"/>
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/drawable/background_cache_hint_selector_quantum_dark.xml
similarity index 69%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/drawable/background_cache_hint_selector_quantum_dark.xml
index 4e88855..7d64abc 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/drawable/background_cache_hint_selector_quantum_dark.xml
@@ -14,10 +14,7 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_accelerated="false" android:color="@android:color/background_quantum_dark" />
+ <item android:color="@android:color/transparent" />
+</selector>
diff --git a/packages/SystemUI/res/anim/notification_dnd_off.xml b/core/res/res/drawable/background_cache_hint_selector_quantum_light.xml
similarity index 69%
copy from packages/SystemUI/res/anim/notification_dnd_off.xml
copy to core/res/res/drawable/background_cache_hint_selector_quantum_light.xml
index 4e88855..3fc3483 100644
--- a/packages/SystemUI/res/anim/notification_dnd_off.xml
+++ b/core/res/res/drawable/background_cache_hint_selector_quantum_light.xml
@@ -14,10 +14,7 @@
limitations under the License.
-->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:fromXDelta="100%p" android:toXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_accelerated="false" android:color="@android:color/background_quantum_light" />
+ <item android:color="@android:color/transparent" />
+</selector>
diff --git a/core/res/res/drawable/btn_default_quantum.xml b/core/res/res/drawable/btn_default_quantum_dark.xml
similarity index 86%
copy from core/res/res/drawable/btn_default_quantum.xml
copy to core/res/res/drawable/btn_default_quantum_dark.xml
index 1affe3a..84b1090 100644
--- a/core/res/res/drawable/btn_default_quantum.xml
+++ b/core/res/res/drawable/btn_default_quantum_dark.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,17 +18,18 @@
<item>
<selector>
<item android:state_window_focused="false" android:state_enabled="true"
- android:drawable="@drawable/btn_default_normal_holo_light" />
+ android:drawable="@drawable/btn_default_normal_holo_dark" />
<item android:state_window_focused="false" android:state_enabled="false"
- android:drawable="@drawable/btn_default_disabled_holo_light" />
+ android:drawable="@drawable/btn_default_disabled_holo_dark" />
<item android:state_focused="true" android:state_enabled="true"
- android:drawable="@drawable/btn_default_focused_holo_light" />
+ android:drawable="@drawable/btn_default_focused_holo_dark" />
<item android:state_enabled="true"
- android:drawable="@drawable/btn_default_normal_holo_light" />
+ android:drawable="@drawable/btn_default_normal_holo_dark" />
<item android:state_focused="true"
- android:drawable="@drawable/btn_default_disabled_focused_holo_light" />
+ android:drawable="@drawable/btn_default_disabled_focused_holo_dark" />
<item
- android:drawable="@drawable/btn_default_disabled_holo_light" />
+ android:drawable="@drawable/btn_default_disabled_holo_dark" />
</selector>
</item>
+ <item android:drawable="@drawable/btn_default_pressed_holo_dark" />
</reveal>
diff --git a/core/res/res/drawable/btn_default_quantum.xml b/core/res/res/drawable/btn_default_quantum_light.xml
similarity index 95%
rename from core/res/res/drawable/btn_default_quantum.xml
rename to core/res/res/drawable/btn_default_quantum_light.xml
index 1affe3a..b559198 100644
--- a/core/res/res/drawable/btn_default_quantum.xml
+++ b/core/res/res/drawable/btn_default_quantum_light.xml
@@ -31,4 +31,5 @@
android:drawable="@drawable/btn_default_disabled_holo_light" />
</selector>
</item>
+ <item android:drawable="@drawable/btn_default_pressed_holo_light" />
</reveal>
diff --git a/core/res/res/drawable/item_background_quantum.xml b/core/res/res/drawable/item_background_quantum.xml
deleted file mode 100644
index 5c44c87..0000000
--- a/core/res/res/drawable/item_background_quantum.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-
-<reveal xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <selector>
- <item android:state_focused="true" android:state_enabled="false"
- android:drawable="@drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true"
- android:drawable="@drawable/list_focused_holo" />
- <item
- android:drawable="@color/transparent" />
- </selector>
- </item>
- <item android:drawable="@drawable/list_selector_background_transition_holo_light" />
-</reveal>
diff --git a/core/res/res/values-ja/bools.xml b/core/res/res/drawable/item_background_quantum_dark.xml
similarity index 71%
copy from core/res/res/values-ja/bools.xml
copy to core/res/res/drawable/item_background_quantum_dark.xml
index 59cf744..5ccaa8e 100644
--- a/core/res/res/values-ja/bools.xml
+++ b/core/res/res/drawable/item_background_quantum_dark.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<resources>
- <bool name="flip_controller_fallback_keys">true</bool>
-</resources>
-
+<reveal xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/transparent" />
+ <item android:drawable="@color/lighter_gray" />
+</reveal>
diff --git a/core/res/res/values-ja/bools.xml b/core/res/res/drawable/item_background_quantum_light.xml
similarity index 71%
rename from core/res/res/values-ja/bools.xml
rename to core/res/res/drawable/item_background_quantum_light.xml
index 59cf744..f1453c5 100644
--- a/core/res/res/values-ja/bools.xml
+++ b/core/res/res/drawable/item_background_quantum_light.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
+<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<resources>
- <bool name="flip_controller_fallback_keys">true</bool>
-</resources>
-
+<reveal xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/transparent" />
+ <item android:drawable="@color/darker_gray" />
+</reveal>
diff --git a/core/res/res/drawable/list_selector_quantum.xml b/core/res/res/drawable/list_selector_quantum.xml
deleted file mode 100644
index d41247c..0000000
--- a/core/res/res/drawable/list_selector_quantum.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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.
--->
-
-<reveal xmlns:android="http://schemas.android.com/apk/res/android">
- <item>
- <selector>
- <item android:state_window_focused="false"
- android:drawable="@color/transparent" />
- <item android:state_focused="true" android:state_enabled="false"
- android:drawable="@drawable/list_selector_disabled_holo_light" />
- <item android:state_focused="true"
- android:drawable="@drawable/list_focused_holo" />
- </selector>
- </item>
- <item android:drawable="@drawable/list_selector_background_transition_holo_light" />
-</reveal>
diff --git a/core/res/res/drawable/list_selector_quantum_dark.xml b/core/res/res/drawable/list_selector_quantum_dark.xml
new file mode 100644
index 0000000..fea55a8
--- /dev/null
+++ b/core/res/res/drawable/list_selector_quantum_dark.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<reveal xmlns:android="http://schemas.android.com/apk/res/android">
+ <selector>
+ <item android:state_window_focused="false" android:drawable="@color/transparent" />
+ <item android:state_focused="true" android:state_enabled="false"
+ android:drawable="@drawable/list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:drawable="@drawable/list_focused_holo" />
+ </selector>
+ <selector>
+ <item android:state_window_focused="false" android:drawable="@color/transparent" />
+ <item android:state_focused="true" android:state_enabled="false"
+ android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_dark" />
+ <item android:state_focused="true" android:state_pressed="true"
+ android:drawable="@drawable/list_selector_background_transition_holo_dark" />
+ <item android:state_focused="false" android:state_pressed="true"
+ android:drawable="@drawable/list_selector_background_transition_holo_dark" />
+ </selector>
+</reveal>
diff --git a/core/res/res/drawable/list_selector_quantum_light.xml b/core/res/res/drawable/list_selector_quantum_light.xml
new file mode 100644
index 0000000..1e32eac
--- /dev/null
+++ b/core/res/res/drawable/list_selector_quantum_light.xml
@@ -0,0 +1,33 @@
+<?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.
+-->
+
+<reveal xmlns:android="http://schemas.android.com/apk/res/android">
+ <selector>
+ <item android:state_window_focused="false" android:drawable="@color/transparent" />
+ <item android:state_focused="true" android:state_enabled="false"
+ android:drawable="@drawable/list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:drawable="@drawable/list_focused_holo" />
+ </selector>
+ <selector>
+ <item android:state_window_focused="false" android:drawable="@color/transparent" />
+ <item android:state_focused="true" android:state_enabled="false"
+ android:state_pressed="true" android:drawable="@drawable/list_selector_disabled_holo_light" />
+ <item android:state_focused="true" android:state_pressed="true"
+ android:drawable="@drawable/list_selector_background_transition_holo_light" />
+ <item android:state_focused="false" android:state_pressed="true"
+ android:drawable="@drawable/list_selector_background_transition_holo_light" />
+ </selector>
+</reveal>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index d74c404..246bda1 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Laat die program toe om enige geïnstalleer mediadekodeerder te gebruik om te kan dekodeer vir terugspeel."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"bestuur vertroude eiebewyse"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Laat die program CA-sertifikate as vertroude eiebewyse installeer en deïnstalleer."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind aan ledige dienste"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Hierdie toestemming laat die Android-stelsel toe om aan \'n program se ledige dienste te bind."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"laat program gedurende ledige tyd loop"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met hierdie toestemming kan die Android-stelsel die program in die agtergrond laat loop terwyl die toestel nie gebruik word nie."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lees/skryf na bronne wat diag besit"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Laat die program toe om na enige hulpbron wat deur die diag-groep besit word, te skryf, byvoorbeeld lêers in /dev. Dit kan potensieel stelselstabiliteit en sekuriteit affekteer. Dit moet NET gebruik word vir hardewarespesifieke diagnose deur die vervaardiger of operateur."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktiveer of deaktiveer programkomponente"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Laat die program toe om die foonkenmerke van die toestel te beheer. \'n Program met hierdie toestemming kan tussen netwerke wissel, die foonradio aan en af skakel, en dies meer, sonder om jou ooit te laat weet."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lees foonstatus en identiteit"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Laat die program toe om toegang tot die foonfunksies van die toestel te verkry. Hierdie toestemming laat die program toe om te bepaal wat die foonnommer en toestel-IDs is, of die oproep aan die gang is, en die afgeleë nommer wat deur \'n oproep verbind word."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lees presiese foonstate"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Gee die program toegang tot presiese foonstate. Hierdie toestemming laat die program toe om die werklike oproepstatus te bepaal, of \'n oproep aktief is en of dit in die agtergrond is. Dit kan ook mislukte oproepe, presiese dataverbindingstatus en mislukte dataverbindings bepaal."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"verhoed dat tablet slaap"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"verhoed foon om te slaap"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Laat die program toe om die tablet te keer om te slaap."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 56bdd24..4f38a82 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ለመልሰህ አጫውት ፍታን በማንኛውም የተጫኑ በማህደረ መረጃ ዲኮደር ለመጠቀም ለመተግበሪያ ይፈቅዳል።"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"የታመኑ ምስክርነቶችን ያስተዳድሩ"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"መተግበሪያው CA የምስክር ወረቀቶችን እንደሚታመኑ ምስክርነቶች አንዲጭን እና እንዲያራግፍ ይፍቀዱ።"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"ከስራ ፈት አገልግሎቶች ጋር ይሰሩ"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ይህ ፍቃድ የAndroid ስርዓቱ የአንድ መተግበሪያ ስራ-ፈት አገልግሎቶችን እንዲያስር ያስችለዋል።"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"ስራ በተፈታበት ጊዜ ላይ መተግበሪያውን አሂድ"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ይህ ፍቃድ መሣሪያው ስራ ላይ ባልሆነ ጊዜ የAndroid ስርዓቱ መተግበሪያውን በጀርባ ውስጥ እንዲያሂደው ያስችለዋል።"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"በdiag ባለቤትነት ያሉ ንብረቶችን አንብብ/ፃፍ"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"በዲያግ ቡድን ባለቤትነት ወደ አለ ማንኛውም ንብረት ለምሳሌ በ/dev ያሉ ፋይሎች ለማንበብ እና ለመፃፍ ለመተግበሪያው ይፈቅዳሉ። ይህ በመሰረቱ የስርዓት መረጋጋትን እና ደህንነትን ሊጎዳ ይችላል። ይህ ውስን የሀርድዌር-ተኮር ዲያግኖስቲክስ በአምራቹ ወይም ከዋኙ ብቻ መሆን አለበት።"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"የመተግበሪያ ምንዝሮችን አንቃ ወይም አቦዝን"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"የመገልገያ መሳሪያውን የስልክ ባህሪያት ለመቆጣጠር ለመተግበሪያው ይፈቅዳል፡፡ ከዚህ ፍቃድ ጋር መተግበሪያ አውታረ መረቦችን ሊለውጥ ይችላል፤አንተን ምንም ሳያሳውቅ የስልኩን ሬድዮ አብራ እና አጥፋ እና የመሳሰሉትን ሊያበራ ይችላል፡፡"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"የስልክ ሁኔታና ማንነት አንብብ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"መተግበሪያው የመሳሪያውን የስልክ ባህሪያት ላይ እንዲደርስ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው የስልክ ቁጥሩን እና የመሳሪያውን መታወቂያዎች፣ ጥሪ የነቃ እንደሆነ፣ እና በጥሪ የተገናኘውን የሩቅ ቁጥር እንዲወስን ይፈቅድለታል።"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ትክክለኛዎቹን የስልክ ሁኔታዎች ያነብባል"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"መተግበሪያው ትክክለኛዎቹ የስልክ ሁኔታዎችን እንዲደርስባቸው ያስችለዋል። ይህ ፍቃድ መተግበሪያው የእውነተኛ ጥሪው ሁኔታ፣ አንድ ጥሪ ገባሪ ወይም ጀርባ ላይ ይሁን፣ ያልተሳኩ ጥሪዎች፣ ትክክለኛው የውሂብ ግንኙነት ሁኔታ እና የውሂብ ግንኙነት አለመሳካቶችን እንዲያውቅ ያስችለዋል።"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ጡባዊ ከማንቀላፋት ተከላከል"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ስልክ ከማንቀላፋት ተከላከል"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ጡባዊውን ከመተኛት መከልከል ለመተግበሪያው ይፈቅዳሉ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 56addd1..2c3549d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"السماح للتطبيق باستخدام أي برنامج فك تشفير وسائط مثبت لفك التشفير من أجل التشغيل."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"إدارة بيانات الاعتماد الموثوقة"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"السماح للتطبيق بتثبيت شهادات CA وإلغاء تثبيتها باعتبارها بيانات اعتماد محل ثقة."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"الالتزام بالخدمات الخاملة"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"يتيح هذا الإذن لنظام Android الارتباط بخدمات وضع الخمول لأحد التطبيقات."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"تشغيل التطبيق أثناء وقت الخمول"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"يتيح هذا الإذن لنظام Android تشغيل التطبيق في الخلفية في حين أن الجهاز ليس قيد الاستخدام."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"قراءة/كتابة إلى الموارد المملوكة بواسطة التشخيص"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"للسماح للتطبيق بالقراءة والكتابة إلى أي مورد مملوك بواسطة مجموعة التشخيصات؛ على سبيل المثال، الملفات في /dev. من المحتمل أن يؤثر ذلك في استقرار النظام وأمانه. يجب ألا يستخدم ذلك سوى للتشخيصات الخاصة بالنظام من قِبل المصنِّع أو المشغِّل."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"تمكين مكونات التطبيق أو تعطيلها"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"للسماح للتطبيق بالتحكم في ميزات الهاتف بالجهاز. يمكن لأحد التطبيقات بهذا الإذن تبديل الشبكات وتشغيل لاسلكي الهاتف وإيقاف تشغيله وما إلى ذلك بدون إعلامك على الإطلاق."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"قراءة حالة الهاتف والهوية"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"للسماح للتطبيق بالدخول إلى ميزات الهاتف في الجهاز. ويتيح هذا الإذن للتطبيق تحديد رقم الهاتف ومعرّفات الجهاز، وما إذا كانت هناك مكالمة نشطة والرقم البعيد الذي تم الاتصال به في المكالمة."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"قراءة حالات الهاتف الدقيقة"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"للسماح للتطبيق بالوصول إلى حالات الهاتف الدقيقة. يتيح هذا الإذن للتطبيق تحديد حالة المكالمة الفعلية، سواء أكانت مكالمة نشطة أم في الخلفية، وإخفاق الاتصال، وحالة اتصال البيانات الدقيقة، وإخفاق اتصال البيانات."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"منع الجهاز اللوحي من الدخول في وضع السكون"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"منع الهاتف من الدخول في وضع السكون"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"للسماح للتطبيق بمنع الجهاز اللوحي من الانتقال إلى وضع السكون."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 218d54a..af7f9e8 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Разрешава на приложението да използва всеки инсталиран медиен декодер с цел декодиране за възпроизвеждане."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управление на надеждните идентификационни данни"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Разрешава на приложението да инсталира и деинсталира сертификати от сертифициращи органи като надеждни идентификационни данни."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"обвързване с услуги при неактивност"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Това разрешение позволява на системата Android да се свързва с неактивните услуги на приложението."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"изпълняване на приложението по време на неактивност"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Това разрешение позволява на системата Android да изпълнява приложението на заден план, докато устройството не се използва."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"четене/запис в ресурси, притежавани от diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Разрешава на приложението да чете и записва във всеки ресурс, притежаван от групата diag, например файловете в /dev. Това потенциално може да засегне стабилността и сигурността на системата. То трябва да се използва САМО за диагностика, конкретно за хардуера, от страна на производителя или оператора."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"активиране или деактивиране на компоненти на приложенията"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Разрешава на приложението да контролира телефонните функции на устройството. Приложение с такова разрешение може да превключва между мрежи, да включва и изключва радиомодула на телефона и други подобни, без изобщо да ви известява."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"четене на състоянието и идентификационните данни на телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Разрешава на приложението достъп до телефонните функции на устройството. Това разрешение позволява на приложението да определя телефонния номер и идентификационния номер на устройството, дали се води разговор и отдалечения номер, до който е установена връзка с обаждането."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"четене на точните състояния на телефона"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Позволява на приложението да осъществява достъп до точните състояния на телефона. С това разрешение то може да определи действителното състояние на обаждането – дали е активно, или е на заден план, дали е неуспешно, точното състояние на връзката за пренос на данни и неуспешната връзка за пренос."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"предотвратяване на спящия режим на таблета"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"предотвратява спящ режим на телефона"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Разрешава на приложението да предотвратява преминаването на таблета в спящ режим."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 415e248..50c7187 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet que l\'aplicació utilitzi qualsevol descodificador de mitjans instal·lat per descodificar per a la reproducció."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestiona les credencials de confiança"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet que l\'aplicació instal·li i desinstal·li certificats de CA com a credencials de confiança."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincula als serveis inactius"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Amb aquest permís, el sistema Android podrà vincular-se amb els serveis inactius d\'una aplicació."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"executar l\'aplicació durant el temps d\'inactivitat"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Aquest permís permet que el sistema Android executi l\'aplicació en segon pla mentre el dispositiu no està en ús."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"llegir/escriure recursos propietat de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet que l\'aplicació llegeixi i escrigui a qualsevol recurs propietat del grup diag; per exemple, els fitxers de /dev. Això podria afectar l\'estabilitat i la seguretat del sistema. NOMÉS l\'hauria d\'utilitzar el fabricant o l\'operador per a diagnòstics específics de maquinari."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activa o desactiva els components de l\'aplicació"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet que l\'aplicació controli les funcions de telèfon del dispositiu. Una aplicació amb aquest permís pot canviar de xarxa, activar i desactivar el senyal mòbil i dur a terme accions semblants sense notificar-t\'ho."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"veure l\'estat i la identitat del telèfon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet que l\'aplicació accedeixi a les funcions de telèfon del dispositiu. Aquest permís permet que l\'aplicació determini el número de telèfon i els identificadors del dispositiu, si hi ha una trucada activa i el número remot connectat amb una trucada."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"llegeix els estats exactes del telèfon"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet que l\'aplicació accedeixi als estats exactes del telèfon. Amb aquest permís, l\'aplicació pot determinar l\'estat real de la trucada, si la trucada està activa o en segon pla, si s\'ha produït algun error, l\'estat exacte de la connexió de dades i els errors de la connexió de dades."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evita que la tauleta entri en mode d\'inactivitat"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el telèfon entri en mode de repòs"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet que l\'aplicació impedeixi que la tauleta entri en repòs."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c338661..010f812 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikaci používat libovolný nainstalovaný dekodér médií k dekódování při přehrávání."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"správa důvěryhodných identifikačních údajů"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikaci instalovat a odinstalovat certifikáty CA jako důvěryhodné identifikační údaje."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"napojit se na nečinné služby"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto oprávnění umožní systému Android vázat se na nečinné služby aplikace."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"spustit aplikaci během nečinnosti"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto oprávnění umožňuje systému Android spustit aplikaci na pozadí, když zařízení není používáno."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čtení nebo zápis do prostředků funkce diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikaci číst libovolné prostředky ve skupině diag, např. soubory ve složce /dev, a zapisovat do nich. Může dojít k ovlivnění stability a bezpečnosti systému. Toto nastavení by měl používat POUZE výrobce či operátor pro diagnostiku hardwaru."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivace či deaktivace komponent aplikací"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Umožňuje aplikaci ovládat telefonní funkce zařízení. Aplikace s tímto oprávněním smí bez upozornění přepínat sítě, zapínat a vypínat bezdrátový modul telefonu a podobně."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čtení stavu a identity telefonu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikaci získat přístup k telefonním funkcím zařízení. Toto oprávnění umožňuje aplikaci zjistit telefonní číslo telefonu, identifikační čísla zařízení, zda zrovna probíhá hovor, a vzdálené číslo, ke kterému je hovor připojen."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čtení přesného stavu telefonování"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikaci zjišťovat přesný stav telefonování a mobilních dat. Toto oprávnění aplikaci umožňuje zjistit skutečný stav volání, zda je volání aktivní nebo na pozadí, zda volání selhalo, přesný stav datového připojení a zda datové připojení selhalo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"bránění přechodu tabletu do režimu spánku"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"bránění přechodu telefonu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikaci zabránit přechodu tabletu do režimu spánku."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index bd4a3ec..07474b7 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillader, at appen bruger enhver installeret medieafkoder til at afkode til afspilning."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålidelige logonoplysninger"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillader, at appen installerer og afinstallerer CA-certifikater som pålidelige loginoplysninger."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt til tjenester i dvale"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med denne tilladelse kan Android-systemet bindes til en applikations dvaletjenester."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"kør applikation, mens enheden er i dvale"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med denne tilladelse kan Android-systemet køre applikationen i baggrunden, mens enheden ikke er i brug."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"læs/skriv til ressourcer ejet af diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillader, at appen kan læse og skrive til alle ressourcer, der ejes af diag-gruppen, f.eks. filer i /dev. Dette kan muligvis påvirke systemets stabilitet og sikkerhed. Dette bør KUN bruges til hardwarespecifik diagnosticering, som foretages af producenten eller udbyderen."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Tillader, at appen kan styre enhedens telefonfunktioner. En app med denne tilladelse kan skifte netværk, slå telefonsenderen til og fra og lignende uden at underrette dig."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"læse telefonens status og identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillader, at appen kan få adgang til telefonfunktionerne på enheden. Med denne tilladelse kan appen fastslå telefonnummeret og enheds-id\'erne, hvorvidt et opkald er aktivt samt det eksterne nummer, der oprettes forbindelse til via et opkald."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"læse nøjagtig status for telefonen"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Tillader, at appen får adgang til den nøjagtige status for telefonen. Denne tilladelse giver appen mulighed for at fastlægge den rigtige opkaldsstatus – om et opkald er aktivt eller kører i baggrunden, om opkaldet mislykkes, hvad den nøjagtige status for dataforbindelsen er, og om dataforbindelsen mislykkes."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"afholde tabletcomputeren fra at gå i dvale"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"afholde telefonen fra at gå i dvale"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillader, at appen kan forhindre tabletten i at gå i dvale."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4da2043..5d2515f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ermöglicht der App, alle installierten Mediendecodierer zur Wiedergabe zu verwenden."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Vertrauenswürdige Anmeldedaten verwalten"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ermöglicht der App, CA-Zertifikate als vertrauenswürdige Anmeldedaten zu installieren und zu deinstallieren."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"An inaktive Dienste binden"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Mit dieser Berechtigung kann sich das Android-System an die inaktiven Dienste einer App binden."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"App bei Inaktivität ausführen"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Diese Berechtigung ermöglicht es dem Android-System, die App im Hintergrund auszuführen, wenn das Gerät nicht verwendet wird."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ermöglicht der App, alle Elemente in der Diagnosegruppe zu lesen und zu bearbeiten, etwa Dateien in \"/dev\". Dies könnte eine potenzielle Gefährdung für die Stabilität und Sicherheit des Systems darstellen und sollte NUR für hardwarespezifische Diagnosen des Herstellers oder Mobilfunkanbieters verwendet werden."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"App-Komponenten aktivieren oder deaktivieren"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ermöglicht der App, die Telefonfunktionen des Geräts zu steuern. Eine App mit dieser Berechtigung kann das Netzwerk wechseln oder das Radio des Telefons ein- und ausschalten, ohne Sie darüber zu informieren."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Telefonstatus und Identität abrufen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ermöglicht der App, auf die Telefonfunktionen des Geräts zuzugreifen. Die Berechtigung erlaubt der App, die Telefonnummer und Geräte-IDs zu erfassen, festzustellen, ob gerade ein Gespräch geführt wird, und die Rufnummer verbundener Anrufer zu lesen."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Genaue Telefonstatusangaben abrufen"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ermöglicht der App, auf die genauen Telefonstatusangaben zuzugreifen. Diese Erlaubnis ermöglicht der App, den tatsächlichen Rufstatus zu ermitteln, das bedeutet, ob ein Anruf aktiv ist oder im Hintergrund abläuft, ob bei einem Anruf ein Fehler aufgetreten ist, wie der genaue Datenverbindungsstatus lautet oder ob bei der Datenverbindung ein Fehler aufgetreten ist."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Ruhezustand des Tablets deaktivieren"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Ruhezustand deaktivieren"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ermöglicht der App, den Ruhezustand des Tablets zu deaktivieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 9e06e2a..8f297e14 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Επιτρέπει στην εφαρμογή τη χρήση οποιουδήποτε εγκατεστημένου αποκωδικοποιητή μέσων για αναπαραγωγή."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"διαχείριση αξιόπιστων διαπιστευτηρίων"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Επιτρέπει στην εφαρμογή την εγκατάσταση και την απεγκατάσταση πιστοποιητικών CA ως αξιόπιστων διαπιστευτηρίων."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"σύνδεση σε υπηρεσίες αδράνειας"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Αυτή η άδεια επιτρέπει στο σύστημα Android να συνδέεται στις υπηρεσίες αδράνειας μιας εφαρμογής."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"εκτέλεση εφαρμογής κατά τη λειτουργία αδράνειας"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Αυτή η άδεια επιτρέπει στο σύστημα Android να εκτελεί την εφαρμογή στο παρασκήνιο όταν δεν χρησιμοποιείται η συσκευή."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ανάγνωση/εγγραφή σε πόρους που ανήκουν στο διαγνωστικό"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Επιτρέπει στην εφαρμογή την ανάγνωση και την εγγραφή σε οποιονδήποτε πόρο που ανήκει στην ομάδα διαγνωστικού (π.χ. αρχεία στον κατάλογο /dev). Αυτό ενδέχεται να επηρεάσει την σταθερότητα και την ασφάλεια του συστήματος. Θα πρέπει να χρησιμοποιείται ΜΟΝΟ για διαγνωστικά υλικού από τον κατασκευαστή ή τον χειριστή."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ενεργοποίηση ή απενεργοποίηση στοιχείων εφαρμογής"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Επιτρέπει στην εφαρμογή να ελέγχει τις λειτουργίες τηλεφώνου της συσκευής. Μια εφαρμογή η οποία διαθέτει αυτήν την άδεια μπορεί να κάνει εναλλαγή μεταξύ δικτύων, να ενεργοποιεί και να απενεργοποιεί το ραδιόφωνο του τηλεφώνου και άλλα, χωρίς να ειδοποιείστε."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ανάγνωση κατάστασης και ταυτότητας τηλεφώνου"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Επιτρέπει στην εφαρμογή την πρόσβαση στις λειτουργίες τηλεφώνου της συσκευής. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να καθορίζει τον αριθμό τηλεφώνου και τα αναγνωριστικά συσκευών, εάν μια κλήση είναι ενεργή, καθώς και τον απομακρυσμένο αριθμό που συνδέεται από μια κλήση."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ανάγνωση ακριβούς κατάστασης τηλεφώνου"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Επιτρέπει στην εφαρμογή να αποκτήσει πρόσβαση στην ακριβή κατάσταση του τηλεφώνου. Αυτή η άδεια επιτρέπει στην εφαρμογή να καθορίσει την πραγματική κατάσταση της κλήσης, εάν η κλήση είναι ενεργή ή πραγματοποιείται στο παρασκήνιο, αποτυχίες κλήσεων, ακριβή δεδομένα κατάστασης σύνδεσης και αποτυχίες σύνδεσης δεδομένων."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"παρεμπόδιση μετάβασης του tablet σε κατάσταση αδράνειας"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"παρεμπόδιση μετάβασης του τηλεφώνου σε κατάσταση αδράνειας"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Επιτρέπει στην εφαρμογή την παρεμπόδιση της μετάβασης του tablet σε κατάσταση αδράνειας."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index a4b2f93..c5158498 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Allows the app to control the phone features of the device. An app with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"read precise phone states"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Allows the app to access the precise phone states. This permission allows the app to determine the real call status, whether a call is active or in the background, call fails, precise data connection status and data connection fails."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index a4b2f93..c5158498 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Allows the app to use any installed media decoder to decode for playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"manage trusted credentials"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Allows the app to install and uninstall CA certificates as trusted credentials."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"bind to idle services"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"This permission allows the Android system to bind to an application\'s idle services."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"run application during idle time"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"This permission allows the Android system to run the application in the background while the device is not in use."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"read/write to resources owned by diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Allows the app to read and write to any resource owned by the diag group; for example, files in /dev. This could potentially affect system stability and security. This should ONLY be used for hardware-specific diagnostics by the manufacturer or operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"enable or disable app components"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Allows the app to control the phone features of the device. An app with this permission can switch networks, turn the phone radio on and off and the like without ever notifying you."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"read phone status and identity"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Allows the app to access the phone features of the device. This permission allows the app to determine the phone number and device IDs, whether a call is active and the remote number connected by a call."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"read precise phone states"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Allows the app to access the precise phone states. This permission allows the app to determine the real call status, whether a call is active or in the background, call fails, precise data connection status and data connection fails."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"prevent tablet from sleeping"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"prevent phone from sleeping"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Allows the app to prevent the tablet from going to sleep."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f8e789c..545b317 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"vincular con servicios inactivos"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Este permiso autoriza al sistema Android a vincularse con los servicios inactivos de una aplicación."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Con este permiso, el sistema Android puede ejecutar la aplicación en segundo plano mientras el dispositivo no está en uso."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación lea y escriba en cualquier recurso propiedad del grupo de diagnóstico como, por ejemplo, archivos in/dev. Este permiso podría afectar la seguridad y estabilidad del sistema. SOLO se debe utilizar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activar o desactivar componentes de la aplicación"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Una aplicación con este permiso puede cambiar redes, encender y apagar la radio del teléfono y tareas similares sin siquiera notificártelo."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"leer la identidad y el estado del dispositivo"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"leer estados precisos del teléfono"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que la aplicación acceda a los estados precisos del teléfono y determine el estado real de la llamada, si hay una llamada activa o en segundo plano, si se produjeron fallos en la llamada, el estado preciso de la conexión de datos y si hubo fallos relacionados con la conexión de datos."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"evitar que el tablet entre en estado de inactividad"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar que el dispositivo entre en estado de inactividad"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación evite que la tablet entre en estado de inactividad."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5010841..515caca 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que la aplicación use cualquier decodificador de archivos multimedia instalado para la reproducción."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrar credenciales de confianza"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que la aplicación instale y desinstale certificados de CA como credenciales de confianza."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"ocultar para servicios inactivos"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esto permite que el sistema Android enlace con servicios inactivos de una aplicación."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"ejecutar la aplicación durante el tiempo de inactividad"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esto permite que el sistema Android ejecute la aplicación en segundo plano mientras el dispositivo no se utiliza."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer/escribir en los recursos propiedad del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que la aplicación consulte y escriba en cualquier recurso del grupo de diagnóstico como, por ejemplo, archivos en /dev. Este permiso podría afectar a la seguridad y estabilidad del sistema. SOLO se debe usar para diagnósticos específicos de hardware realizados por el fabricante o el operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"habilitar o inhabilitar componentes de la aplicación"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que la aplicación controle las funciones de teléfono del dispositivo. Las aplicaciones que tengan este permiso pueden cambiar de red, desactivar la señal móvil, etc., sin necesidad de informar al usuario."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"consultar la identidad y el estado del teléfono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que la aplicación acceda a las funciones de teléfono del dispositivo. La aplicación puede utilizar este permiso para descubrir identificadores de dispositivos y números de teléfono, para saber si una llamada está activa y para conocer el número remoto con el que se ha establecido conexión mediante una llamada."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"leer estados precisos del teléfono"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que la aplicación acceda a estados precisos del teléfono y que pueda determinar el estado real de la llamada, si una llamada está activa o en segundo plano, si se ha producido un error en la llamada, el estado de conexión de datos preciso y si se ha producido un error en la conexión de datos."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que el tablet entre en modo de suspensión"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir que el teléfono entre en modo de suspensión"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que la aplicación impida que el tablet entre en modo de suspensión."</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 29feb3e..988ab47 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Võimaldab rakendusel taasesituseks kasutada mis tahes installitud meediumidekooderit."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"usaldusväärsete mandaatide haldamine"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lubab rakendusel installida ja desinstallida usaldusväärsete mandaatidena CA-sertifikaate."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"sidumine tegevusetute teenustega"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"See luba võimaldab Androidi süsteemil siduda end rakenduse tegevusetute teenustega."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"rakenduse käitamine tegevusetul ajal"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"See luba võimaldab Android-süsteemil käitada rakendust taustal siis, kui seadet ei kasutata."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"loe/kirjuta valija allikaid"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Võimaldab rakendusel lugeda valimisrühma mis tahes ressurssi ja sellesse kirjutada (näiteks kaustas /dev olevad failid). See võib mõjutada süsteemi stabiilsust ja turvet. Seda tohiks kasutada tootja või operaator AINULT riistvaraspetsiifiliseks diagnostikaks."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Rakenduse komponentide lubamine või keelamine"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Võimaldab rakendusel juhtida seadme telefonifunktsioone. Selle loaga rakendus saab vahetada võrke, lülitada telefoniraadiot sisse ja välja ning teha muudki ilma teid teavitamata."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lugege telefoni olekut ja identiteeti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Annab rakendusele juurdepääsu seadme telefonifunktsioonidele. See luba võimaldab rakendusel määrata telefoninumbri ja seadme ID-d ning kontrollida, kas kõne on aktiivne ja kaugnumber on kõne kaudu telefoniga ühendatud."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"telefoni täpsete olekute lugemine"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Lubab rakendusel hankida juurdepääsu telefoni täpsetele olekutele. Selle loa korral saab rakendus tuvastada kõne tõelise oleku, kas kõne on aktiivne või taustal, kõnede ebaõnnestumised, täpse andmesideühenduse oleku ja andmesideühenduse ebaõnnestumised."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tahvelarvuti uinumise vältimine"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"väldi telefoni uinumist"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Võimaldab rakendusel vältida tahvelarvuti uinumist."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 34ee392..1f2a6cc 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"اجازه میدهد برنامه از هر رمزگشای رسانه نصب شدهای استفاده کند تا برای پخش رمزگشایی شود."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"مدیریت اطلاعات کاربری مورد اعتماد"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"به برنامه امکان میدهد گواهینامههای CA را به عنوان اطلاعات کاربری مورد اعتماد نصب یا حذف نصب کند."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"اتصال با سرویسهای غیرفعال"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"این مجوز به سیستم Android امکان میدهد به سرویسهای غیرفعال یک برنامه متصل شود."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"اجرای برنامه در هنگام بدون فعالیت بودن دستگاه"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"این مجوز به سیستم Android امکان میدهد تا وقتی دستگاه استفاده نمیشود برنامه را در پسزمینه اجرا کند."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"خواندن/نوشتن منابع متعلق به تشخیص"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"به برنامه اجازه میدهد هر منبعی را که متعلق به گروه تشخیص است بخواند و در آن بنویسد؛ بهعنوان مثال، فایلهای /dev. این امر بهصورت بالقوه میتواند بر پایدار بودن و امنیت سیستم تأثیر بگذارد. این تنها باید برای تشخیصهای مختص سختافزار توسط تولیدکننده یا اپراتور استفاده شود."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"فعال یا غیر فعال کردن اجزای برنامه"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"به برنامه اجازه میدهد ویژگیهای دستگاه را کنترل کند. برنامهای که این مجوز را دارد میتواند بدون اطلاع شما تعویض شبکه داشته باشد، رادیوی تلفن را روشن یا خاموش کند و کارهایی از این قبیل را انجام دهد."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"خواندن وضعیت تلفن و شناسه"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"به برنامه اجازه میدهد به ویژگیهای تلفن دستگاه شما دسترسی پیدا کند. این مجوز به برنامه اجازه میدهد شماره تلفن و شناسههای دستگاه، فعال بودن یک تماس و شماره راه دوری که با یک تماس متصل شده است را مشخص کند."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"خواندن وضعیتهای دقیق تلفن"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"به برنامه امکان میدهد به وضعیتهای دقیق تلفن دسترسی داشته باشد. این مجوز به برنامه امکان میدهد وضعیت واقعی تماس، اینکه آیا تماس فعال است یا در پسزمینه قرار دارد، تماسهای ناموفق، وضعیت دقیق اتصال داده و اتصالهای ناموفق داده را تعیین کند."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ممانعت از به خواب رفتن رایانهٔ لوحی"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ممانعت از به خواب رفتن تلفن"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"به برنامه اجازه میدهد تا از غیرفعال شدن رایانهٔ لوحی جلوگیری کند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 01f37d5..cbec12b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Sallii sovelluksen käyttää mitä tahansa asennettua tietovälineen koodin purkajaa toistoa varten."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hallinnoi luotettavia varmenteita"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Antaa sovellukselle luvan asentaa ja poistaa luotettavia CA-varmenteita."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"sido käyttämättömiin palveluihin"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Tämä käyttöoikeus antaa Android-järjestelmän sitoa sovelluksen käyttämättömiä palveluita."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"suorita sovellus laitteen ollessa käyttämättömänä"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Tämä oikeus sallii Android-järjestelmän siirtää sovelluksen suorituksen taustalle, kun laite ei ole käytössä."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lue diag:in omistamia resursseja / kirjoita resursseihin"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Antaa sovelluksen lukea ja kirjoittaa diag-ryhmän omistamiin resursseihin, esimerkiksi /dev-hakemistossa oleviin tiedostoihin. Tämä voi vaikuttaa järjestelmän vakauteen ja turvallisuuteen. Tämä lupa tulee myöntää VAIN valmistajan tai operaattorin laitteistotesteille."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"sovelluskomponenttien ottaminen käyttöön tai pois käytöstä"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Antaa sovelluksen hallita laitteen puhelinominaisuuksia. Jos sovelluksella on tämä oikeus, se voi esimerkiksi vaihtaa verkkoa tai ottaa puhelinradion käyttöön tai poistaa sen käytöstä ilmoittamatta käyttäjälle."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lue puhelimen tila ja identiteetti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Antaa sovelluksen käyttää laitteen puhelinominaisuuksia. Sovellus voi määrittää puhelinnumeron ja laitteen tunnuksen, puhelun tilan sekä soitetun numeron."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lue puhelimen tarkat tilat"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Antaa sovelluksen käyttää puhelimen tarkkoja tiloja. Tämän oikeus antaa sovelluksen määrittää puhelun todellisen tilan, eli onko puhelu aktiivinen vai taustalla, puhelujen epäonnistumiset, tietoliikenneyhteyden tarkan tilan ja tietoliikenneyhteyden muodostuksen epäonnistumiset."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"estä tablet-laitetta menemästä virransäästötilaan"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"estä puhelinta menemästä virransäästötilaan"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Antaa sovelluksen estää tablet-laitetta siirtymästä virransäästötilaan."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index fe29fb8f..91749e6 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"lier aux services inactifs"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plateforme Android de se lier aux services inactifs d\'une application."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lire ou modifier les ressources appartenant au groupe de diagnostics"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture et en écriture pour toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Cela peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou le fournisseur de services."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants d\'une application"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet à l\'application de contrôler les fonctionnalités de téléphonie de l\'appareil. Une application disposant de cette autorisation peut, par exemple, basculer d\'un réseau à l\'autre et activer ou désactiver le signal radio du téléphone à votre insu."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Accéder aux états précis du téléphone"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet à l\'application d\'accéder aux états précis du téléphone. Cette autorisation lui permet de déterminer le statut d\'appel réel, si un appel est actif ou en arrière-plan, si des appels ont échoué, l\'état précis de la connexion et si cette dernière a échoué."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index dae681d..51f0f76 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permet à une application d\'utiliser n\'importe quel décodeur installé pour lire les fichiers multimédias."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gérer les certificats de confiance"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permet à l\'application d\'installer et de désinstaller les certificats CA en tant que certificats de confiance."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"associer aux services d\'inactivité"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Cette autorisation permet à la plate-forme Android de se lier aux services inactifs d\'une application."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"exécuter l\'application lorsque l\'appareil est inactif"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cette autorisation permet au système Android d\'exécuter l\'application en arrière-plan lorsque l\'appareil est inactif."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lecture/écriture dans les ressources appartenant aux diagnostics"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permet à l\'application d\'obtenir des droits en lecture/écriture concernant toute ressource appartenant au groupe de diagnostics (par exemple, les fichiers du répertoire /dev). Ceci peut affecter la stabilité et la sécurité du système. Cette fonctionnalité est UNIQUEMENT réservée aux diagnostics matériels effectués par le fabricant ou l\'opérateur."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activer ou désactiver les composants de l\'application"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permet à l\'application de contrôler les fonctionnalités de téléphonie de l\'appareil. Une application disposant de cette autorisation peut, par exemple, basculer d\'un réseau à l\'autre et activer ou désactiver le signal radio du téléphone à votre insu."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"voir l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permet à l\'application d\'accéder aux fonctionnalités téléphoniques de l\'appareil. Cette autorisation permet à l\'application de déterminer le numéro de téléphone et les identifiants de l\'appareil, si un appel est actif et le numéro distant connecté par un appel."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Accéder aux états précis du téléphone"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permet à l\'application d\'accéder aux états précis du téléphone. Cette autorisation lui permet de déterminer le statut d\'appel réel, si un appel est actif ou en arrière-plan, si des appels ont échoué, l\'état précis de la connexion et si cette dernière a échoué."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"empêcher la tablette de passer en mode veille"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permet à l\'application d\'empêcher la tablette de passer en mode veille."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f0c005d..b35c14f 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ऐप्स को प्लेबैक डीकोड करने के लिए किसी भी इंस्टॉल किए गए डीकोडर का उपयोग करने देता है."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"विश्वसनीय क्रेडेंशियल प्रबंधित करें"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ऐप्स को CA प्रमाणपत्रों को विश्वसनीय क्रेडेंशियल के रूप में इंस्टॉल और अनइंस्टॉल करने दें"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"निष्क्रिय सेवाओं से आबद्ध करें"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"यह अनुमति Android सिस्टम को किसी एप्लिकेशन की निष्क्रिय सेवाओं से आबद्ध होने देती है."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"निष्क्रिय समय के दौरान एप्लिकेशन चलाएं"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"यह अनुमति Android सिस्टम को उपकरण के उपयोग में नहीं रहने पर एप्लिकेशन को पृष्ठभूमि में चलाने देती है."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"निदान के स्वामित्व वाले संसाधनों को पढ़ें/लिखें"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ऐप्स को diag समूह के स्वामित्व वाले किसी संसाधन को पढ़ने और उसमें लिखने देता है; उदाहरण के लिए, /dev की फ़ाइलें. यह सिस्टम की स्थिरता और सुरक्षा को संभावित रूप से प्रभावित कर सकता है. इसका उपयोग निर्माता या ऑपरेटर द्वारा केवल हार्डवेयर-विशिष्ट निदान के लिए किया जाना चाहिए."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ऐप्स घटकों को सक्षम या अक्षम करें"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ऐप्स को उपकरण की फ़ोन सुविधाएं नियंत्रित करने देता है. इस अनुमति वाला कोई ऐप्स आपको सूचित किए बिना नेटवर्क स्विच कर सकता है, फ़ोन का रेडियो चालू और बंद कर सकता है और ऐसे ही अन्य कार्य कर सकता है."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"फ़ोन की स्थिति और पहचान पढ़ें"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ऐप्स को उपकरण की फ़ोन सुविधाओं तक पहुंचने देता है. यह अनुमति ऐप्स को फ़ोन नंबर और उपकरण आईडी, कॉल सक्रिय है या नहीं, और कॉल द्वारा कनेक्ट किया गया दूरस्थ नंबर निर्धारित करने देती है."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"सटीक फ़ोन स्थितियों को पढ़ना"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ऐप्स को सटीक फ़ोन स्थितियों की एक्सेस देती है. यह अनुमति ऐप्स को कॉल की वास्तविक स्थिति, चाहे वह कॉल सक्रिय हो या पृष्ठभूमि में हो, कॉल विफलताओं, सटीक डेटा कनेक्शन की स्थिति और डेटा कनेक्शन विफलताओं का पता लगाने देती है."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टेबलेट को निष्क्रिय होने से रोकें"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फ़ोन को निष्क्रिय होने से रोकें"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ऐप्स को टेबलेट को प्रयोग में नहीं हो जाने से रोकता है."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 5b7a098..b048bbc 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Aplikaciji omogućuje korištenje bilo kojim instaliranim dekoderom medija za dekodiranje radi reprodukcije."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje pouzdanim vjerodajnicama"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Omogućuje aplikaciji instaliranje i deinstaliranje CA certifikata kao pouzdanih vjerodajnica."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"veži uz usluge u mirovanju"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dopuštenje omogućuje sustavu Android da se veže uz aplikacijine usluge u mirovanju."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"izvodi aplikaciju tijekom mirovanja"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dopuštenje omogućuje sustavu Android da izvodi aplikaciju u pozadini dok se uređaj ne upotrebljava."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"pisanje/čitanje u resursima čije je vlasnik dijagnostika"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Aplikaciji omogućuje čitanje i pisanje na bilo koji resurs u vlasništvu dijag. grupe; na primjer, datoteke u sustavu /dev. To bi moglo utjecati na stabilnost sustava i sigurnost. Dozvolu bi trebao upotrebljavati proizvođač ili operater SAMO za dijagnostiku koja se odnosi na hardver."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"omogućavanje ili onemogućavanje komponenti aplikacije"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Omogućuje aplikaciji upravljanje telefonskim značajkama uređaja. Aplikacija s tom dozvolom može izmjenjivati mreže, uključiti i isključiti radiouređaj telefona i tome slično, a da vas o tome uopće ne obavijesti."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čitanje statusa i identiteta telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogućuje pristup telefonskim značajkama uređaja. Ta dozvola aplikaciji omogućuje utvrđivanje telefonskog broja i ID-ova uređaja, je li poziv aktivan te udaljeni broj koji je povezan pozivom."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čitaj precizna stanja telefona"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Omogućuje aplikaciji pristup preciznim stanjima telefona. To dopuštenje omogućuje aplikaciji da odredi stvarni status poziva, je li poziv aktivan ili u pozadini, neuspjele pozive, precizne podatke o statusu veze te neuspjela uspostavljanja podatkovnih veza."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"spriječi mirovanje tabletnog uređaja"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"sprečava telefon da prijeđe u stanje mirovanja"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Aplikaciji omogućuje sprječavanje prelaska tabletnog računala u mirovanje."</string>
@@ -633,7 +635,7 @@
<string name="permlab_bluetooth" msgid="6127769336339276828">"uparivanje s Bluetooth uređajima"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na tabletnom računalu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Aplikaciji omogućuje pregled konfiguracije Bluetootha na telefonu te uspostavljanje i prihvaćanje veza s uparenim uređajima."</string>
- <string name="permlab_nfc" msgid="4423351274757876953">"upravljaj beskontaktnom (NFC) komunikacijom"</string>
+ <string name="permlab_nfc" msgid="4423351274757876953">"upravljanje beskontaktnom komunikacijom (NFC)"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Aplikaciji omogućuje komunikaciju s oznakama, karticama i čitačima komunikacije kratkog dometa (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"onemogućavanje zaključavanja zaslona"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Aplikaciji omogućuje onemogućavanje zaključavanja tipkovnice i svih pripadajućih sigurnosnih zaporki. Na primjer, telefon onemogućuje zaključavanje tipkovnice kod primanja dolaznog telefonskog poziva, nakon kojeg se zaključavanje tipkovnice ponovo omogućuje."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index c48ca2a..1547900 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lehetővé teszi egy alkalmazás számára bármely telepített médiadekóder használatát a lejátszás dekódolásához."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"megbízható tanúsítványok kezelése"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lehetővé teszi az alkalmazás számára a CA tanúsítványok telepítését és eltávolítását."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"csatolás tétlen szolgáltatásokhoz"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ez az engedély lehetővé teszi az Android számára, hogy összekapcsolódjon egy alkalmazás tétlen szolgáltatásaival."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"alkalmazás futtatása tétlen időszakban"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ezzel az engedéllyel az Android a háttérben futtathatja az alkalmazást, amikor az eszközt nem használják."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"a diag tulajdonában lévő erőforrások olvasása és írása"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Lehetővé teszi egy alkalmazás számára, hogy olvassa és írja a diagnosztikai csoport minden erőforrását, például a /dev könyvtárban lévő fájlokat. Ez potenciálisan befolyásolhatja a rendszer stabilitását és biztonságát, ezért CSAK a gyártó vagy a szolgáltató használhatja hardverspecifikus diagnosztizálásra."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"alkalmazáskomponensek be- és kikapcsolása"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Lehetővé teszi az alkalmazás számára, hogy az eszköz telefonálási funkcióit vezérelje. Egy ilyen engedéllyel rendelkező alkalmazás váltani tud a hálózatok között, be- és kikapcsolhatja a telefon rádióját, és hasonlókat tehet anélkül, hogy valaha értesítené Önt."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonállapot és azonosító olvasása"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lehetővé teszi az alkalmazás számára, hogy hozzáférjen az eszköz telefonálási funkcióihoz. Az engedéllyel rendelkező alkalmazás meghatározhatja a telefonszámot és eszközazonosítókat, hogy egy hívás aktív-e, valamint híváskor a másik fél telefonszámát."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"pontos telefonállapot megállapítása"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Engedélyezi, hogy az alkalmazás hozzáférjen a pontos telefonállapothoz. Az ilyen engedéllyel rendelkező alkalmazás képes meghatározni a valós hívási állapotot, azt, hogy egy hívás aktív-e vagy a háttérben van, a hívás meghiúsult-e, illetve képes meghatározni az adatkapcsolat pontos állapotát és az adatkapcsolati műveletek meghiúsulását."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"táblagép alvás üzemmódjának megakadályozása"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefon alvó üzemmódjának megakadályozása"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lehetővé teszi az alkalmazás számára, hogy megakadályozza, hogy a táblagép alvó üzemmódra váltson."</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index c544ddb..77b8070 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Թույլ է տալիս հավելվածին օգտագործել ցանկացած տեղադրված մեդիա վերծանիչ` նվագարկումը ապակոդավորելու համար:"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"կառավարել վստահելի հավաստագրերը"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Թույլատրում է հավելվածին տեղադրել և ապատեղադրել CA վկայագրերը՝ որպես վստահելի հավաստագրեր:"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"կապակցել ոչ ակտիվ ծառայությունների հետ"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Այս թույլտվությունը հնարավորություն է տալիս Android համակարգին կապ հաստատել ծրագրի չաշխատող ծառայությունների հետ:"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"գործադրել ծրագրեր պարապուրդի ժամանակ"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Այս թույլտվությունը հնարավորություն է տալիս, որ Android համակարգը ծրագրեր գործադրի ֆոնային ռեժիմում, երբ սարքը չի օգտագործվում:"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"կարդալ կամ գրել ախտորոշիչին պատկանող ռեսուրսները"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Թույլ է տալիս հավելվածին կարդալ և գրել ախտորոշիչ խմբին պատկանող ցանկացած ռեսուրսում, ինչպես օրինակ ֆայլերը /dev-ում: Դա կարող է ազդել համակարգի կայունության և անվտանգության վրա: Սա պետք է օգտագործել միայն արտադրողի կամ օպերատորի կողմից սարքին հատուկ ախտորոշման համար:"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"միացնել կամ անջատել հավելվածի բաղադրիչները"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Թույլ է տալիս հավելվածին կառավարել սարքի հեռախոսային գործիքները: Այս թույլտվությամբ հավելվածը կարող է փոխարկել ցանցերը, միացնելև անջատել հեռախոսի ռադիոն և նման այլ բաներ` առանց ձեզ երբևէ տեղեկացնելու:"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"կարդալ հեռախոսի կարգավիճակը և ինքնությունը"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Թույլ է տալիս հավելվածին օգտագործել սարքի հեռախոսային գործիքները: Այս թույլտվությունը հավելվածին հնարավորություն է տալիս որոշել հեռախոսահամարը և սարքի ID-ները, արդյոք զանգը ակտիվ է և միացված զանգի հեռակա հեռախոսահամարը:"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"դիտել հեռախոսի ճշգրիտ կարգավիճակները"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Թույլ է տալիս ծրագրին մուտք ունենալ հեռախոսի ճշգրիտ կարգավիճակներին: Այս թույլատվության շնորհիվ ծրագիրը կարող է որոշել զանգի իրական կարգավիճակը, արդյոք զանգը ակտիվ է, թե հետին պլանում է, զանգերի ժամանակ տեղի ունեցած սխալները, տվյալների միացման ճշգրիտ կարգավիճակը և տվյալների միացման ժամանակ տեղի ունեցած սխալները:"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"զերծ պահել գրասալիկը քնելուց"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"կանխել հեռախոսի քնի ռեժիմին անցնելը"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Թույլ է տալիս հավելվածին կանխել գրասալիկի` քնի ռեժիմին անցնելը:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index c144c60..de49cba 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Mengizinkan apl menggunakan pengawasandi media apa pun yang terpasang guna mengawasandikan media untuk diputar."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"kelola kredensial tepercaya"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Izinkan aplikasi memasang dan mencopot pemasangan sertifikat CA sebagai kredensial tepercaya."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"mengikat ke layanan yang sedang menganggur"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Izin ini memungkinkan sistem Android mengikat layanan waktu menganggur aplikasi."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"menjalankan aplikasi selama waktu nganggur"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Izin ini memungkinkan sistem Android menjalankan aplikasi di latar belakang saat perangkat tidak digunakan."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber daya yang dimiliki oleh diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Mengizinkan apl membaca dan menulis ke sumber daya apa pun yang dimiliki oleh grup diag; misalnya, file dalam /dev. Izin ini berpotensi memengaruhi kestabilan dan keamanan sistem. Sebaiknya ini HANYA digunakan untuk diagnosis khusus perangkat keras oleh pabrikan atau operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"mengaktifkan atau menonaktifkan komponen apl"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Mengizinkan apl mengontrol fitur telepon perangkat. Apl dengan izin ini dapat mengalihkan jaringan, menyalakan dan mematikan radio ponsel, dan melakukan hal serupa lainnya tanpa pernah memberi tahu Anda."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"baca identitas dan status ponsel"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"membaca keadaan ponsel dengan akurat"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Memungkinkan aplikasi mengakses keadaan ponsel dengan akurat. Izin ini memungkinkan aplikasi menentukan status panggilan yang sebenarnya, apakah panggilan sedang aktif atau di latar belakang, kegagalan panggilan, status sambungan data yang akurat, dan kegagalan sambungan data."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"cegah tablet dari tidur"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"mencegah ponsel menjadi tidak aktif"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Mengizinkan apl mencegah tablet tidur."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index a16e5d0..808a3be 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Consente all\'applicazione di utilizzare qualsiasi decoder multimediale installato per la decodifica ai fini della riproduzione."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestione di credenziali attendibili"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Consente all\'app di installare e disinstallare certificati CA come credenziali attendibili."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"associazione a servizi non disponibili"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Questa autorizzazione consente al sistema Android di associarsi ai servizi inattivi di un\'applicazione."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"esegui l\'applicazione nel tempo di inattività del sistema"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Questa autorizzazione consente al sistema Android di eseguire l\'applicazione in background mentre il dispositivo non è in uso."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lettura/scrittura risorse di proprietà di diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Consente all\'applicazione di leggere le risorse del gruppo diag e scrivere in esse, ad esempio i file in /dev. Ciò potrebbe influire su stabilità e sicurezza del sistema. Dovrebbe essere utilizzata SOLTANTO per diagnostiche specifiche dell\'hardware effettuate dal produttore o dall\'operatore."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"attivazione/disattivazione componenti applicazioni"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Consente all\'applicazione di controllare le funzioni telefoniche del dispositivo. Un\'applicazione con questa autorizzazione può cambiare rete, attivare/disattivare il segnale radio del telefono e così via a tua insaputa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"rileva gli stati esatti del telefono"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Consente all\'app di accedere allo stato esatto del telefono. Questa autorizzazione consente all\'app di determinare il reale stato della chiamata: se una chiamata è attiva, in sottofondo o non riuscita. Inoltre, rileva l\'esatto stato della connessione dati nonché le connessioni dati non riuscite."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 20218f2..096c4ed 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"הרשאה זו מאפשרת לאפליקציה להשתמש בכל מפענח מדיה מותקן כדי לבצע פענוח להשמעה."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ניהול פרטי כניסה מהימנים"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"מאפשרת לאפליקציה להתקין ולהסיר אישורי CA כפרטי כניסה מהימנים."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"אגד עם שירותים במצב לא פעיל"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ההרשאה הזו מאפשרת למערכת Android לאגד אל שירותי אפליקציה במצב לא פעיל."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"הרצת אפליקציה בזמן מצב לא פעיל"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ההרשאה הזו מאפשרת למערכת Android להריץ את האפליקציה ברקע כשהמכשיר אינו בשימוש."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"קרא/כתוב במשאבים בבעלות diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"מאפשר לאפליקציה לקרוא ולכתוב בכל משאב שבבעלות קבוצת ה-diag; לדוגמה, קבצים ב-/dev. פעולה זו עשויה להשפיע על היציבות והאבטחה של המערכת. אפשרות זו צריכה לשמש רק את היצרן או המפעיל, לצורך אבחונים ספציפיים לחומרה."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"הפעלה או השבתה של רכיבי אפליקציות"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"מאפשר לאפליקציה לשלוט בתכונות הטלפון של המכשיר. אפליקציה בעלת הרשאה זו יכולה לעבור בין רשתות, להפעיל ולכבות את הרדיו בטלפון ולבצע פעולות נוספות דומות מבלי ליידע אותך."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"קריאת הסטטוס והזהות של הטלפון"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"מאפשר לאפליקציה לגשת לתכונות הטלפון של המכשיר. אישור זה מתיר לאפליקציה לגלות את מספר הטלפון ואת זיהויי המכשיר, האם שיחה פעילה ואת המספר המרוחק המחובר באמצעות שיחה."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"קריאת מצבי טלפון מדויקים"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"מאפשר לאפליקציה לגשת למצבי הטלפון המדויקים. ההרשאה הזו מאפשרית לאפליקציה לדעת מה סטטוס השיחה בפועל, האם שיחה פעילה או ברקע, כשלי שיחות, סטטוס מדויק על חיבור נתונים וכשלים בחיבור נתונים."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"מנע מהטאבלט לעבור למצב שינה"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"מניעת מעבר הטלפון למצב שינה"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"מאפשר לאפליקציה למנוע מהטאבלט לעבור למצב שינה."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 58495e8..8f5d7fe 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"インストール済みのメディアデコーダーを使用して再生用にデコードすることをアプリに許可します。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"信頼できる認証情報の管理"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"CA証明書を信頼できる認証情報としてインストールしたりアンインストールしたりすることをアプリに許可します。"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"アイドルサービスへのバインディング"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"この許可により、Androidシステムはアプリのアイドルサービスにバインディングできるようになります。"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"アイドル状態でのアプリの実行"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"この権限により、端末が使用中でない場合でもAndroidシステムがバックグラウンドでアプリを実行できるようになります。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"diagグループが所有するリソース(/dev内のファイルなど)の読み書きをアプリに許可します。許可すると、システムの安定性とセキュリティに影響が生じる可能性があります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"アプリのコンポーネントの有効/無効化"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"端末の電話機能の制御をアプリに許可します。許可すると、アプリではユーザーに通知なくネットワークの切り替え、無線通信のON/OFFなどを行えるようになります。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"端末のステータスとIDの読み取り"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"端末の電話機能へのアクセスをアプリに許可します。これにより、電話番号、端末ID、通話中かどうか、通話相手の電話番号をアプリから特定できるようになります。"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"正確な電話ステータスの読み取り"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"正確な電話ステータスにアクセスすることをアプリに許可します。これにより、実際の発信ステータス(発信がアクティブか、バックグラウンドか)、発信エラー、正確なデータ接続ステータス、データ接続エラーをアプリから特定できるようになります。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"タブレットのスリープを無効化"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"端末のスリープを無効にする"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"タブレットのスリープを無効にすることをアプリに許可します。"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index c82b606..8bb038c 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"აპს დასაკრავად შეეძლება გამოიყენოს ნებისმიერი დაყენებული მედია დეკოდერი."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"სანდო მტკიცებულებების მართვა"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"აპისთვის ნების დართვა, მოახდინოს CA სერტიფიკატების სანდო მტკიცებულებებად ინსტალაცია და დეინსტალაცია."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"უქმე სერვისებზე მიბმა"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ეს უფლება საშუალებას აძლევს Android-ის სისტემას, განახორციელოს აპლიკაციის უქმე სერვისების მიბმა."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"უქმე მდგომარეობისას აპლიკაციის გაშვება"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ეს უფლება Android-ის სისტემას უფლებას ანიჭებს ფონურად გაუშვას აპლიკაცია, როდესაც მოწყობილობა არ გამოიყენება."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"სისტემის დიაგნოსტიკის რესურსებში წაკითხვა/ჩაწერის უფლება"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"აპს შეეძლება, წაიკითხოს ან ჩაწეროს ნებისმიერ რესურსში, რომელიც დიაგნოსტიკის ჯგუფს ეკუთვნის, მაგალითად, ფაილები /dev-ში. ამან შესაძლოა იმოქმედოს სისტემის სტაბილურობასა და უსაფრთხოებაზე. მისი გამოყენება მხოლოდ მწარმოებლის ან ოპერატორის მიერ ტექნიკის სპეციფიკური დიაგნოსტიკისთვის უნდა მოხდეს."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"აპის კომპონენტების ჩართვა ან გამორთვა"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"აპს შეეძლება აკონტროლოს მოწყობილობაზე ტელეფონის ფუნქციები. ამ უფლების მქონე აპს შეუძლია ქსელების გადართვა, ტელეფონის რადიოს ჩართვა და გამორთვა, მომხმარებლისათვის შეტყობინების გარეშე."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ტელეფონის სტატუსისა და იდენტობის წაკითხვა"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"აპს შეეძლება ჰქონდეს წვდომა მოწყობილობის სატელეფონო ფუნქციებზე. აპმა მსგავსი უფლებით შეძლებს დაადგინოს ტელეფონის ნომერი, მისი სერიული გამოცემა, აქტიური ზარი, დაკავშირებული ნომერი და მსგავსი."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ტელეფონის ზუსტი მდგომარეობების დადგენა"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ანიჭებს აპს ტელეფონის ზუსტ მდგომარეობაზე წვდომას. ეს უფლება საშუალებას აძლევს აპს შეიტყოს ინფორმაცია ზარის რეალურ სტატუსზე, აქტიურია ზარი თუ უკანა ფონზეა, ვერ განხორციელებული ზარები, მონაცემთა გადაცემის ზუსტი სტატუსი და ვერ განხორციელებული მონაცემთა კავშირები."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"დაიცავით ტაბლეტი დაძინებისგან"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ტელეფონის ძილის რეჟიმში გადასვლის აღკვეთა"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"აპს შეეძლება ხელი შეუშალოს ტაბლეტის დაძინებას."</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index f0026be..1d93e2e 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ឲ្យកម្មវិធីប្រើកម្មវិធីឌិកូដមេឌៀដែលបានដំឡើង ដើម្បីឌិកូដសម្រាប់ការចាក់ឡើងវិញ។"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"គ្រប់គ្រងព័ត៌មានសម្ងាត់ដែលទុកចិត្ត"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"អនុញ្ញាតឲ្យកម្មវិធីដំឡើង និងលុបវិញ្ញាបនបត្រ CA នៅពេលមានព័ត៌មានសម្ងាត់ដែលទុកចិត្ត។"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"ភ្ជាប់ទៅសេវាកម្មទំនេរ"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"សិទ្ធិនេះអនុញ្ញាតឲ្យប្រព័ន្ធ Android ចងសេវាកម្មទំនេររបស់កម្មវិធី។"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"ដំណើរការកម្មវិធីអំឡុងពេលទំនេរ"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"សិទ្ធិនេះអនុញ្ញាតឲ្យប្រព័ន្ធ Android ដំណើរការកម្មវិធីក្នុងផ្ទៃខាងក្រោយ ខណៈដែលឧបករណ៍មិនកំពុងប្រើ។"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"អាន/សរសេរធនធានគ្រប់គ្រងប្រអប់"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ឲ្យកម្មវិធីអាន និងសរសេរប្រភពណាមួយដែលគ្រប់គ្រងដោយក្រុមអ្នកវិនិច្ឆ័យ ឧទាហរណ៍ ឯកសារនៅក្នុង /dev ។ វាអាចប៉ះពាល់យ៉ាងខ្លាំងដល់ស្ថេរភាព និងសុវត្ថិភាពប្រព័ន្ធ។ វាគួរត្រូវបានប្រើសម្រាប់វិនិច្ឆ័យផ្នែករឹងជាក់លាក់ដោយក្រុមហ៊ុនផលិត ឬប្រតិបត្តិករ។"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"បិទ ឬបើកសមាសធាតុកម្មវិធី"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ឲ្យកម្មវិធីពិនិត្យលក្ខណៈទូរស័ព្ទនៃឧបករណ៍។ កម្មវិធីដែលមានសិទ្ធិនេះអាចប្ដូរបណ្ដាញ បិទ និងបើកវិទ្យុក្នុងទូរស័ព្ទដោយមិនជូនដំណឹងអ្នក។"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"អានស្ថានភាព និងអត្តសញ្ញាណទូរស័ព្ទ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ឲ្យកម្មវិធីចូលដំណើរការលក្ខណៈទូរស័ព្ទនៃឧបករណ៍។ សិទ្ធិនេះឲ្យកម្មវិធីកំណត់លេខទូរស័ព្ទ និងលេខសម្គាល់ឧបករណ៍ ថាតើការហៅសកម្ម និងលេខពីចម្ងាយបានភ្ជាប់ដោយការហៅ។"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"អានស្ថានភាពទូរស័ព្ទត្រឹមត្រូវ"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ឲ្យកម្មវិធីចូលដំណើរការស្ថានភាពទូរស័ព្ទត្រឹមត្រូវ។ សិទ្ធិនេះអនុញ្ញាតឲ្យកម្មវិធីកំណត់ស្ថានភាពហៅជាក់ស្ដែង ថាតើការហៅសកម្ម ឬស្ថិតក្នុងផ្ទៃខាងក្រោយ ការហៅបរាជ័យ ស្ថានភាពភ្ជាប់ទិន្នន័យត្រឹមត្រូវ និងការភ្ជាប់ទិន្នន័យបរាជ័យ។"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ការពារកុំព្យូទ័របន្ទះមិនឲ្យដេក"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ការពារទូរស័ព្ទមិនឲ្យដេក"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ឲ្យកម្មវិធីការពារកុំព្យូទ័របន្ទះមិនឲ្យដេក។"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5a7f9b8..03542c5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"애플리케이션에서 설치된 모든 미디어 디코더를 사용하여 재생하는 데 디코딩할 수 있도록 허용합니다."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"신뢰할 수 있는 자격증명 관리"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"앱에서 CA 인증서를 신뢰할 수 있는 자격증명으로 설치 및 제거하도록 허용합니다."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"유휴 서비스에 연결"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"이 권한을 부여하면 Android 시스템이 애플리케이션의 유휴 서비스에 연결할 수 있습니다."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"유휴 시간 동안 애플리케이션 실행"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"이 권한을 부여하면 기기를 사용하지 않는 동안 Android 시스템이 백그라운드에서 애플리케이션을 실행할 수 있게 됩니다."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"진단 그룹 소유의 리소스 읽기/쓰기"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"앱이 진단 그룹 소유의 리소스(예: /dev에 있는 파일)를 읽고 쓸 수 있도록 허용합니다. 이 기능은 시스템 안정성 및 보안에 영향을 미칠 수 있으므로 제조업체 또는 사업자가 하드웨어 관련 진단을 수행하는 경우에만 사용해야 합니다."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"앱 구성요소 사용 또는 사용 안함"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"앱이 기기의 휴대전화 기능을 관리할 수 있도록 허용합니다. 이 권한을 갖는 앱은 사용자에게 알리지 않고 네트워크를 전환하거나 무선 기능을 켜고 끄는 등의 작업을 수행할 수 있습니다."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"휴대전화 상태 및 ID 읽기"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"앱이 기기의 휴대전화 기능에 액세스할 수 있도록 허용합니다. 이 권한을 사용하면 앱이 전화번호 및 기기의 ID, 활성 통화인지 여부, 통화가 연결된 원격 번호 등을 확인할 수 있습니다."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"정확한 전화 상태 읽기"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"앱이 정확한 전화 상태에 액세스할 수 있도록 허용합니다. 이 권한을 부여하면 앱이 실제 통화 상태, 활성 통화 또는 백그라운드 상태인지 여부, 통화 실패, 정확한 데이터 연결 상태 및 데이터 연결 실패 등을 판단합니다."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"태블릿이 절전 모드로 전환되지 않도록 설정"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"휴대전화가 절전 모드로 전환되지 않도록 설정"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"앱이 태블릿의 절전 모드 전환을 막도록 허용합니다."</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index abca9cd..4c90dbe 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"ອະນຸຍາດໃຫ້ແອັບຯໃຊ້ທຸກຕົວຖອດລະຫັດສື່ທີ່ຕິດຕັ້ງໄວ້ແລ້ວ ເພື່ອການຖອດລະຫັດການຫຼິ້ນໄຟລ໌ຕ່າງໆ."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"ຈັດການໜັງສືຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"ອະນຸຍາດໃຫ້ແອັບຯ ຕິດຕັ້ງ ແລະ ຖອນການຕິດຕັ້ງໃບຢັ້ງຢືນ CA ທີ່ເປັນໃບຮັບຮອງທີ່ເຊື່ອຖືໄດ້."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"ເຊື່ອມຫາບໍລິການທີ່ບໍ່ໄດ້ນໍາໃຊ້"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"ສິດນີ້ຈະອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດຜູກກັບການບໍລິການຂອງແອັບພລິເຄຊັນທີ່ບໍ່ໄດ້ເຮັດວຽກຢູ່ໄດ້."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"ເປີດແອັບພລິເຄຊັນໃນເວລາທີ່ບໍ່ເຮັດວຽກ"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"ນີ້ຈະເປັນການອະນຸຍາດໃຫ້ລະບົບ Android ສາມາດເປີດແອັບພລິເຄຊັນໃນພື້ນຫຼັງໄດ້ໃນຂະນະທີ່ອຸປະກອນບໍ່ຖືກນຳໃຊ້."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ອ່ານ/ຂຽນ ໃສ່ຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິໄຈ"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນອ່ານ ແລະຂຽນ ໃສ່ທຸກຊັບພະຍາກອນທີ່ເປັນຂອງກຸ່ມວິນິໄສ; ຕົວຢ່າງ: ໄຟລ໌ໃນ /dev. ສິ່ງນີ້ອາດສົ່ງຜົນກະທົບຕໍ່ຄວາມສະຖຽນ ແລະຄວາມປອດໄພຂອງລະບົບ. ສິ່ງນີ້ຄວນໃຊ້ສຳຫຼັບການວິເຄາະບັນຫາຈຳເພາະ ຂອງບາງຮາດແວໂດຍຜູ່ຜະລິດ ຫຼືຜູ່ປະຕິບັດການເທົ່ານັ້ນ."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ເປີດ ຫຼືປິດນຳໃຊ້ອົງປະກອບຂອງແອັບຯ"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມຄວາມສາມາດຂອງໂທລະສັບໃນອຸປະກອນ. ແອັບຯທີ່ມີການອະນຸຍາດນີ້ຈະສາມາດສະລັບເຄືອຂ່າຍ, ເປີດ ຫຼືປິດສັນຍານວິທະຍຸ ແລະຄວາມສາມາດອື່ນທີ່ຄ້າຍກັນ ໂດຍບໍ່ມີການແຈ້ງເຕືອນທ່ານ."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ອ່ານສະຖານະ ແລະຂໍ້ມູນລະບຸໂຕຕົນຂອງໂທລະສັບ"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"ອະນຸຍາດໃຫ້ແອັບຯ ເຂົ້າເຖິງຄວາມສາມາດການໂທລະສັບຂອງອຸປະກອນ. ການກຳນົດສິດນີ້ເຮັດໃຫ້ແອັບຯສາມາດກວດສອບເບີໂທລະສັບ ແລະ ID ຂອງອຸປະກອນ, ບໍ່ວ່າການໂທຈະຍັງດຳເນີນຢູ່ ແລະເບີປາຍທາງເຊື່ອມຕໍ່ຢູ່ຫຼືບໍ່ກໍຕາມ."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ອ່ານຄ່າສະຖານະລະອຽດຂອງໂທລະສັບ"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ອະນຸຍາດໃຫ້ແອັບຯເຂົ້າເຖິງສະຖານະໂດຍລະອຽດຂອງໂທລະສັບ. ການອະນຸຍາດນີ້ຈະຍິນຍອມໃຫ້ແອັບຯກວດສອບສະຖານະການໂທແທ້ໆ ວ່າກຳລັງດຳເນີນຢູ່ ຫຼືຢູ່ໃນແບັກກຣາວ, ຄວາມລົ້ມເຫລວຂອງການໂທ, ສະຖານະການເຊື່ອມຕໍ່ຂໍ້ມູນແບບລະອຽດ ແລະຄວາມລົ້ມເຫລວຂອງການເຊື່ອມຕໍ່ຂໍ້ມູນ."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ຂັດຂວາງບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ຂັດຂວາງບໍ່ໃຫ້ໂທລະສັບປິດໜ້າຈໍ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"ອະນຸຍາດໃຫ້ແອັບຯ ປ້ອງກັນບໍ່ໃຫ້ປິດໜ້າຈໍແທັບເລັດ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index c4e7d11..a8cb3d2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Leidžiama programai naudoti bet kurį įdiegtą medijos dekoderį norint iššifruoti atkūrimą."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"tvarkyti patikimus prisijungimo duomenis"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Programoje galima įdiegti ir iš jos pašalinti CA sertifikatus kaip patikimus prisijungimo duomenis."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"susaistyti su neaktyviomis paslaugomis"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Šiuo leidimu „Android“ sistemai leidžiama susaistyti su programos neaktyviomis paslaugomis."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"paleisti programą, kai įrenginys yra neaktyvus"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Šiuo leidimu sistemai „Android“ leidžiama fone paleisti programą, kai įrenginys yra nenaudojamas."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"skaityti / rašyti ištekliuose, priklausančiuose diagnostikai"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Leidžiama programai skaityti ir rašyti visuose diagnostikos grupei priklausančiuose ištekliuose, pvz., failuose, esančiuose /dev. Tai gali paveikti sistemos stabilumą ir saugą. Tai turėtų būti naudojama TIK gamintojui ar operatoriui atliekant aparatinės įrangos diagnostiką."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"įgalinti programos komponentus arba jų neleisti"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Leidžiama programai valdyti įrenginio telefono funkcijas. Šį leidimą turinti programa gali perjungti tinklus, įjungti ir išjungti telefono radiją ir atlikti panašius veiksmus jūsų neįspėdama."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"skaityti telefono būseną ir tapatybę"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Leidžiama programai pasiekti telefono funkcijas įrenginyje. Šis leidimas suteikia teisę programai nustatyti telefono numerį ir įrenginio ID, tai, ar skambutis aktyvus, ir skambučiu prijungtą nuotolinį numerį."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"skaityti tikslias telefono būsenas"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Programai leidžiama pasiekti tikslias telefono būsenas. Šiuo leidimu programai leidžiama nustatyti tikrą skambučio būseną, ar skambutis yra aktyvus, ar vyksta fone, ar paskambinti nepavyksta, tikslią duomenų ryšio būseną ir ar nepavyksta užmegzti duomenų ryšio."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"neleisti planšetiniam kompiuteriui užmigti"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"neleisti telefonui snausti"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Leidžiama programai neleisti planšetiniam kompiuteriui užmigti."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 4ba1f96..33dd64f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ļauj lietotnei izmantot jebkuru instalētu multivides failu dekodētāju, lai dekodētu failus atskaņošanai."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Uzticamo akreditācijas datu pārvaldība"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ļauj lietotnei instalēt un atinstalēt CA sertifikātus kā uzticamus akreditācijas datus."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"saistīšana ar neaktīviem pakalpojumiem"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Pamatojoties uz šo atļauju, Android sistēma var izveidot saiti ar lietojumprogrammas neaktīvajiem pakalpojumiem."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"Lietojumprogrammas darbība dīkstāves laikā"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ar šo atļauju Android sistēmā lietojumprogramma darbojas fonā, kad ierīce netiek lietota."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lasīt grupas “diag” resursus un rakstīt tajos"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ļauj lietotnei lasīt un rakstīt jebkurā resursā, kas pieder diagnostikas grupai, piemēram, failiem mapē /dev. Tas var ietekmēt sistēmas stabilitāti un drošību. Var izmantot ražotājs vai operators TIKAI konkrētas aparatūras diagnostikai."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"iespējot vai atspējot lietotnes komponentus"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ļauj lietotnei kontrolēt ierīces tālruņa funkcijas. Lietotne, kurai ir šī atļauja, var pārslēgt tīklus, ieslēgt un izslēgt tālruņa radio un veikt tamlīdzīgas darbības, nebrīdinot jūs."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lasīt tālruņa statusu un identitāti"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ļauj lietotnei piekļūt ierīces tālruņa funkcijām. Ar šo atļauju lietotne var noteikt tālruņa numuru un ierīču ID, zvana statusu un attālo numuru, ar ko ir izveidots savienojums, veicot zvanu."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"precīzu tālruņa statusa datu lasīšana"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ļauj lietotnei piekļūt precīziem datiem par tālruņa statusu. Izmantojot šo atļauju, lietotne var noteikt zvana faktisko statusu, vai zvans ir aktīvs vai notiek fonā, vai zvans nav izdevies, kā arī precīzu datu savienojuma statusu un neizdevušos datu savienojumus."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"novērst planšetdatora pāriešanu miega režīmā"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"novērst tālruņa pāriešanu miega režīmā"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ļauj lietotnei novērst planšetdatora pāriešanu miega režīmā."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 0d2da73..1590063 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Апп нь тоглуулах үедээ код тайлахдаа суулгагдсан ямарч медиа код тайлагчийг ашиглах боломжтой."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"итгэмжлэгдсэн жуухуудыг удирдах"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Апп-д CA сертификатуудыг итгэмжлэгдсэн жуух байдлаар суулгах болон устгахыг зөвшөөрнө."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"идэвхгүй үйлчилгээнүүдтэй холбогдох"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Энэ зөвшөөрөл Андройд системд аппликешний идэвхгүй үйлчилгээтэй холбогдох боломж олгоно."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"Сул зогсолтын хугацаанд аппликешнийг ажиллуулна"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Энэ зөвшөөрөл нь Андройд системд төхөөрөмжийг ашиглахгүй байгаа үед аппликешныг далд ажиллуулах боломж олгоно."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"оношлох грүпийн эзэмшдэг нөөцрүү унших/бичих"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Апп нь оношлох грүпийн эзэмшдэг, жишээ нь /dev доторх файлууд, дурын нөөцийг унших бичих боломжтой.Энэ нь системийн тогвортой байдал болон аюулгүй байдалд бодитоор нөлөөлнө. Энэ нь үйлдвэрлэгч болон операторын хардверт-зориулсан оношлогоонд ашиглагдана."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"апп компонентыг идэвхжүүлэх эсвэл идэвхгүй болгох"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Апп-н төхөөрөмжийн утасны функцийг удирдах боломжтой. Энэ зөвшөөрөлтэй апп нь танд анхааруулахгүйгээр сүлжээг сэлгэх, утасны радиог асаах, унтраах боломжтой."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"утасны статус ба таниулбарыг унших"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Апп нь төхөөрөмжийн утасны функцд хандах боломжтой. Энэ зөвшөөрөл нь апп-д утасны дугаар болон төхөөрөмжийн ID-г, дуудлага идэвхтэй эсэх, холын дугаар дуудлагаар холбогдсон байгаа эсэхийг тогтоох боломжийг олгоно,"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"утасны байдлыг нарийн унших"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Апп-д утасны тодорхой байдалд хандах боломжийг олгодог. Энэ зөвшөөрөл апп-д дуудлагын бодит статус, дуудлага идэвхтэй эсхүл ар талд тавигдсан эсэх, амжилтгүй дуудлага болон дата холболтын нарийн статус болон дата холболтын алдааг тодорхойлох боломж олгоно."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"таблетыг унтуулахгүй байлгах"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"утсыг унтуулахгүй байлгах"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Апп нь таблетыг унтахаас сэргийлэх боломжтой"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 6ebdfe1..d5382ab 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Membenarkan apl untuk menggunakan sebarang penyahkod media yang dipasangkan untuk menyahkod main semula."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"urus bukti kelayakan yang dipercayai"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Membenarkan apl memasang dan menyahpasang sijil CA sebagai bukti kelayakan yang dipercayai."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"diikat ke perkhidmatan melahu"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Kebenaran ini membolehkan sistem Android mengikat kepada perkhidmatan melahu aplikasi."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"jalankan aplikasi pada masa melahu"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Kebenaran ini membolehkan sistem Android menjalankan aplikasi di latar belakang semasa peranti tidak digunakan."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"baca/tulis ke sumber yang dimiliki oleh diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Membenarkan apl membaca dan menulis ke sebarang sumber yang dimiliki oleh kumpulan diag; contohnya, fail dalam /dev. Hal ini berpotensi menjejaskan kestabilan dan keselamatan sistem. Perkara ini seharusnya HANYA digunakan untuk diagnosis khusus perkakasan oleh pengilang atau pengendali."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"dayakan atau lumpuhkan komponen apl"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Membenarkan apl untuk mengawal ciri-ciri telefon peranti. Apl dengan kebenaran ini boleh menukar rangkaian, menghidupkan dan mematikan radio telefon dan sebagainya tanpa memberitahu anda."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"baca status dan identiti telefon"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Membenarkan apl mengakses ciri telefon pada peranti. Kebenaran ini membolehkan apl menentukan nombor telefon dan ID peranti, sama ada panggilan aktif dan nombor jauh yang dihubungkan dengan panggilan."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"baca keadaan telefon yang tepat"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Membenarkan apl mengakses keadaan telefon yang tepat. Kebenaran ini membolehkan apl menentukan status panggilan sebenar, sama ada panggilan aktif atau di latar belakang, kegagalan panggilan, status sambungan data yang tepat dan kegagalan sambungan data."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"menghalang tablet daripada tidur"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"halang telefon daripada tidur"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Membenarkan apl menghalang tablet daripada tidur."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 26b27fb..6eae123 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Lar appen bruke en hvilken som helst installert mediedekoder for å dekode for avspilling."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"administrer pålitelig legitimasjon"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Lar appen installere og avinstallere CA-sertifikater som pålitelig legitimasjon."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"knytt til inaktive tjenester"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Denne tillatelsen gjør at Android-systemet kan binde seg til appers inaktive tjenester."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"kjør appen når den ikke er i bruk"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Denne tillatelsen gjør at Android-systemet kan kjøre appen i bakgrunnen mens enheten ikke er i bruk."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lese/skrive ressurser eid av diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Lar appen lese og skrive til alle ressurser som eies av gruppen «diag», som for eksempel filer i /dev. Dette kan potensielt påvirke systemets sikkerhet og stabilitet. Dette bør BARE brukes av produsenten eller operatøren til maskinvarespesifikk diagnostikk."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivere eller deaktivere appkomponenter"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Lar appen kontrollere telefonfunksjonene til enheten. En app som har denne tillatelsen kan bytte nettverk, slå telefonens radio på og av og lignende, uten å varsle deg i det hele tatt."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lese telefonstatus og -identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Lar appen bruke enhetens telefonfunksjoner. Med denne tillatelsen kan appen finne telefonnummer og enhets-ID-er, registrere om en samtale pågår, og se det eksterne nummeret det opprettes en forbindelse med via oppringing."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"lese nøyaktige telefontilstander"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Gir appen tilgang til nøyaktige telefontilstander. Denne tillatelsen gjør at appen kan fastslå den faktiske anropstatusen, om et anrop er aktivt eller i bakgrunnen, anropsfeil, nøyaktig status for datatilkobling og datatilkoblingsfeil."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"hindre nettbrettet fra å gå over til sovemodus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"forhindre telefonen fra å sove"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Lar appen hindre nettbrettet fra å gå over i sovemodus."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b8a7122..09497dc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Hiermee kan de app alle geïnstalleerde mediadecoders gebruiken om te decoderen voor het afspelen."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"vertrouwde inloggegevens beheren"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Hiermee kan de app CA-certificaten installeren en verwijderen als vertrouwde inloggegevens."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"koppelen aan inactieve services"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Met deze toestemming kan het Android-systeem koppelen aan de inactieve services van een app."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"app uitvoeren tijdens inactiviteit"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Met dit recht kan het Android-systeem de app op de achtergrond uitvoeren terwijl het apparaat niet wordt gebruikt."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Hiermee kan de app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of provider."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"componenten van apps in- of uitschakelen"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Hiermee kan de app de telefoonfuncties van het apparaat beheren. Een app met deze toestemming kan schakelen tussen netwerken, kan de radio van de telefoon in- en uitschakelen en dergelijke acties uitvoeren zonder dat u hiervan op de hoogte wordt gesteld."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefoonstatus en -identiteit lezen"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een oproep actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"exacte telefoonstatus lezen"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Toestaan dat de app toegang krijgt tot de exacte telefoonstatus. Hiermee kan de app bepalen wat de echte oproepstatus is, of een oproep actief is of zich op de achtergrond bevindt, of er mislukte oproepen zijn, wat de exacte status van de gegevensverbinding is en of er mislukte gegevensverbindingen zijn."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"voorkomen dat tablet overschakelt naar slaapmodus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Hiermee kan de app voorkomen dat de tablet overschakelt naar de slaapmodus."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8aa847f..37dd42d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pozwala aplikacji na użycie dowolnego zainstalowanego dekodera multimediów do odtwarzania."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"zarządzanie zaufanymi danymi uwierzytelniającymi"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Zezwala aplikacji na instalowanie i odinstalowywanie certyfikatów CA jako zaufanych danych uwierzytelniających."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"powiązanie z nieaktywnymi usługami"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To uprawnienie umożliwia powiązanie systemu Android z nieaktywnymi usługami aplikacji."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"uruchom aplikację w czasie bezczynności"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To uprawnienie pozwala systemowi Android uruchomić aplikację w tle, gdy urządzenie nie jest używane."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"czytanie/zapisywanie w zasobach należących do diagnostyki"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Pozwala aplikacji na czytanie i zapisywanie wszystkich zasobów należących do grupy diagnostyki, na przykład plików w katalogu /dev. Może to potencjalnie wpłynąć na stabilność i bezpieczeństwo systemu. Powinno być wykorzystywane WYŁĄCZNIE do diagnozowania sprzętu przez producenta lub operatora."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"włączanie lub wyłączanie składników aplikacji"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Pozwala aplikacji na kontrolowanie funkcji telefonu w urządzeniu. Aplikacja z tymi uprawnieniami może zmieniać, włączać i wyłączać sieci bezprzewodowe itp. bez informowania użytkownika."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"odczytywanie stanu i informacji o telefonie"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pozwala aplikacji na dostęp do funkcji telefonicznych urządzenia. Aplikacja z tym uprawnieniem może odczytać numer telefonu i identyfikator urządzenia, sprawdzić, czy połączenie jest aktywne, oraz poznać numer, z którym jest nawiązane połączenie."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"dokładne rozpoznawanie stanów telefonu"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Pozwala aplikacji dokładnie rozpoznawać stany telefonu. Aplikacja z tym uprawnieniem może określić rzeczywisty stan połączenia, ustalić, czy jest ono aktywne czy znajduje się w tle, odczytać informacje o nieudanych połączeniach, precyzyjnie określić stan połączenia transmisji danych oraz odczytać informacje o błędach transmisji danych."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zapobieganie przechodzeniu tabletu do trybu uśpienia"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zapobieganie przejściu telefonu w stan uśpienia"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pozwala aplikacji na zapobieganie przechodzeniu tabletu do trybu uśpienia."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index b87a4b0..6eb6cb2 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que a aplicação utilize qualquer descodificador de multimédia instalado para descodificar a reprodução."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerir credenciais fidedignas"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que a aplicação instale e desinstale certificados da AC (Autoridade de certificação) como credenciais fidedignas."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Esta autorização permite que o sistema Android seja vinculado aos serviços inativos de uma aplicação."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"executar aplicação durante o tempo de inatividade"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Esta autorização permite ao sistema Android executar a aplicação em segundo plano enquanto o dispositivo não estiver a ser utilizado."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/escrever em recursos propriedade de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite à aplicação ler e escrever em qualquer recurso que seja propriedade do grupo diag; por exemplo, ficheiros em /dev. Isto pode potencialmente afetar a estabilidade e a segurança do sistema e deve ser utilizado APENAS para diagnósticos específicos do hardware pelo fabricante ou pelo operador."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar componentes da aplicação"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que a aplicação controle as funcionalidades de telefone do aparelho. Uma aplicação com esta permissão pode alternar entre redes, ligar/desligar o rádio do telefone e outras coisas semelhantes sem sequer o notificar."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler o estado e a identidade do telemóvel"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que a aplicação aceda às funcionalidades de telefone do dispositivo. Esta autorização permite que a aplicação determine o número de telefone e IDs do dispositivo, se alguma chamada está ativa e qual o número remoto ligado por uma chamada."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ler os estados precisos do telemóvel"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que a aplicação aceda ao estados precisos do telemóvel. Esta autorização permite que a aplicação determine o estado real da chamada, se uma chamada está ativa ou em segundo plano, falhas em chamadas, o estado preciso da ligação de dados e falhas de ligação de dados."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir que o tablet entre em inactividade"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inactividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que a aplicação impeça o tablet de entrar no modo de suspensão."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2cfad8f..3a5b131 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite que o aplicativo use qualquer decodificador de mídia instalado para reprodução."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gerenciar credenciais confiáveis"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite que o aplicativo instale e desinstale certificados CA como credenciais confiáveis."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"associar a serviços inativos"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Permite que o sistema Android seja associado aos serviços inativos de um aplicativo."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"executar o aplicativo durante o tempo ocioso"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Permite que o sistema Android execute o aplicativo em segundo plano enquanto o dispositivo não está em uso."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"ler/gravar em recursos pertencentes ao diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite que um aplicativo leia e grave em qualquer recurso que pertença ao grupo de diagnósticos, por exemplo, arquivos in/dev. Isso pode afetar a estabilidade e a segurança do sistema. Esse recurso deve ser usado APENAS para diagnósticos específicos do hardware realizados pelo fabricante ou pela operadora."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"ativar ou desativar os componentes do aplicativo"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite que o aplicativo controle os recursos de telefone do dispositivo. Um aplicativo com essa permissão pode alternar entre redes, ligar e desligar o rádio do telefone e assim por diante, sem nunca notificá-lo."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ler status e identidade do telefone"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite que o aplicativo acesse os recursos de telefonia do dispositivo. Esta permissão autoriza o aplicativo a determinar o número de telefone e IDs de dispositivo, quando uma chamada está ativa, e o número remoto conectado a uma chamada."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"ler estados precisos do telefone"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite que o aplicativo acesse estados precisos do telefone. Permite que o aplicativo determine o status real da chamada, se uma chamada está ativa em segundo plano, falhas em chamadas, o status preciso da conexão de dados e falhas na conexão de dados."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"impedir modo de inatividade do tablet"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"impedir modo de inatividade do telefone"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite que o aplicativo impeça o tablet de entrar no modo de inatividade."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 407f6ed..f252f50 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -678,9 +678,9 @@
<skip />
<!-- no translation found for permdesc_manageCaCertificates (4015644047196937014) -->
<skip />
- <!-- no translation found for permlab_bindIdleService (7521398788076342815) -->
+ <!-- no translation found for permlab_bindIdleService (816311765497613780) -->
<skip />
- <!-- no translation found for permdesc_bindIdleService (7747505810143356528) -->
+ <!-- no translation found for permdesc_bindIdleService (1767538493214100612) -->
<skip />
<string name="permlab_diagnostic" msgid="8076743953908000342">"leger/scriver en resursas che appartegnan a diagnostics"</string>
<!-- no translation found for permdesc_diagnostic (6608295692002452283) -->
@@ -935,6 +935,10 @@
<skip />
<!-- no translation found for permdesc_readPhoneState (1639212771826125528) -->
<skip />
+ <!-- no translation found for permlab_readPrecisePhoneState (5476483020282007597) -->
+ <skip />
+ <!-- no translation found for permdesc_readPrecisePhoneState (6648009074263855418) -->
+ <skip />
<!-- no translation found for permlab_wakeLock (1531731435011495015) -->
<skip />
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"evitar ch\'il telefon midia en il modus stand-by"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 21c8a11..7610c06 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Permite aplicaţiei să utilizeze orice decodor media instalat pentru a decodifica redarea."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"gestionarea acreditărilor de încredere"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Permite aplicației să instaleze și să dezinstaleze certificate CA ca acreditări de încredere."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"asociați cu serviciile inactive"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Această autorizare permite sistemului Android să se conecteze la serviciile inactive ale unei aplicații."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"rulează aplicația în timp ce dispozitivul este inactiv"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Cu această permisiune, sistemul Android poate rula aplicația în fundal în timp ce dispozitivul nu este utilizat."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"citire/scriere în resursele deţinute de diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Permite aplicaţiei să citească şi să scrie în orice resursă deţinută de grupul diag, de ex., fişierele din /dev. Această permisiune ar putea să afecteze stabilitatea şi securitatea sistemului. Permisiunea trebuie utilizată NUMAI de producător sau de operator pentru diagnostice specifice pentru hardware."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"activare sau dezactivare a componentelor aplicaţiei"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Permite aplicaţiei să controleze funcţiile de telefon ale dispozitivului. O aplicaţie cu această permisiune poate să schimbe reţeaua, să închidă şi să deschidă radioul şi să efectueze alte acţiuni similare, fără să vă înştiinţeze."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea şi identitatea telefonului"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicaţiei să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicaţia stabileşte numărul de telefon şi ID-urile de dispozitiv, dacă un apel este activ, precum şi numărul de la distanţă conectat printr-un apel."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"accesați stările exacte ale telefonului"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Permite aplicației să acceseze stările exacte ale telefonului. Cu această permisiune, aplicația poate să determine starea reală a apelului, dacă apelul este activ sau în fundal, dacă apelul eșuează, starea exactă și întreruperile conexiunii de date."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Permite aplicaţiei să împiedice intrarea tabletei în stare de repaus."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 9bc6bcd..2ffc435 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Приложение сможет использовать любой установленный дешифратор."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"Управление учетными данными"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Приложение сможет устанавливать сертификаты ЦС в качестве надежных учетных данных, а также удалять их."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"привязка неактивных сервисов"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Android сможет подключаться к неактивным сервисам."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"выполнение приложения в спящем режиме"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Система Android сможет выполнять приложение в фоновом режиме, когда устройство не используется."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Чтение/запись данных в системы диагностики"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Приложение сможет считывать и записывать данные системы диагностики (например, файлы в каталоге /dev). Это может повлиять на стабильность и безопасность системы. Это разрешение должно использоваться ТОЛЬКО производителем или оператором для диагностики аппаратного обеспечения."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"Включение/отключение компонентов приложения"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Приложение сможет управлять на устройстве функциями телефона: переключать сети, включать и выключать приемопередатчик, а также выполнять другие подобные действия без уведомления."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"Получение данных о статусе телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Приложение получит доступ к функциям телефона на устройстве. Кроме того, оно сможет определять номера телефонов и серийные номера моделей, состояние активности вызова, а также удаленные номера, с которыми установлено соединение."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Доступ к точным статусам телефона"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Приложение сможет определять точный статус вызовов (активный, в фоновом режиме или сбой), а также статус интернет-соединения (в том числе, если подключиться не удалось)."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"Отключение спящего режима"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"Отключение спящего режима"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Приложение сможет запрещать перевод планшетного ПК в спящий режим."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7f4e0ed..1d5772b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Umožňuje aplikácii používať na reprodukciu ľubovoľný nainštalovaný dekódovač na dekódovanie."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"spravovať dôveryhodné poverenia"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Umožňuje aplikácii inštalovať a odinštalovať certifikáty CA ako dôveryhodné poverenia."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"previazať s nečinnými službami"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Toto povolenie umožní systému Android viazať sa na nečinné služby aplikácie."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"spustiť aplikáciu počas nečinnosti"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Toto povolenie umožňuje systému Android spustiť aplikáciu na pozadí, keď sa zariadenie nepoužíva."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"čítanie alebo zápis do prostriedkov funkcie diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Umožňuje aplikácii čítať ľubovoľné prostriedky v skupine diag, napr. súbory v priečinku /dev, a zapisovať do nich. Môže dôjsť k ovplyvneniu stability a bezpečnosti systému. Toto nastavenie by mal používať IBA výrobca či operátor na diagnostiku hardvéru."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"povoliť alebo zakázať súčasti aplikácie"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Umožňuje aplikácii ovládať telefónne funkcie zariadenia. Aplikácia s týmto povolením môže prepínať siete alebo zapnúť a vypnúť rádio bez toho, aby vás na to upozornila."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"čítať stav a identitu telefónu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Umožňuje aplikácii pristupovať k telefónnym funkciám zariadenia. Aplikácia s týmto povolením môže určiť telefónne číslo a ID zariadenia, či práve prebieha hovor, a vzdialené číslo, s ktorým je prostredníctvom hovoru nadviazané spojenie."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"čítanie presných stavov telefónu"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Umožňuje aplikácii pristupovať k presným stavom telefónu. Toto povolenie umožňuje aplikácii zistiť skutočný stav hovoru, či je hovor aktívny alebo na pozadí, zlyhania hovorov, presný stav dátového pripojenia a zlyhania dátového pripojenia."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zabránenie prechodu tabletu do režimu spánku"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"zabránenie prechodu telefónu do režimu spánku"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Umožňuje aplikácii zabrániť prechodu tabletu do režimu spánku."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 1f1ab78..783b0a4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Programu omogoča, da uporabi kateri koli dekodirnik večpredstavnosti za predvajanje."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"upravljanje preverjenih poverilnic"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Aplikaciji dovoli nameščanje in odstranjevanje potrdil overitelja potrdil kot preverjenih poverilnic."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"vezanje na nedejavne storitve"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"To dovoljenje dovoli sistemu Android vezanje nedejavnih storitev aplikacije."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"izvajanje aplikacije ob nedejavnosti"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"To dovoljenje sistemu Android omogoča, da izvaja aplikacijo v ozadju, ko naprava ni v uporabi."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"branje/pisanje v sredstva, ki so v lasti skupine za diagnostiko"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Programu omogoča branje in pisanje na poljuben vir, ki je v lasti skupine za diagnostiko; na primer datoteke v mapi /dev. To lahko vpliva na stabilnost in varnost sistema. To naj uporablja SAMO izdelovalec ali operater za diagnostiko, specifično za strojno opremo."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"omogočanje ali onemogočanje komponent programa"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Programu omogoča nadziranje telefonskih funkcij naprave. Program lahko s tem dovoljenjem preklaplja omrežja, vklopi ali izklopi radio v telefonu, ne da bi vas obvestil."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"branje stanja in identitete telefona"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Aplikaciji omogoča dostop do funkcij telefona v napravi. S tem dovoljenjem lahko aplikacija določi telefonsko številko in ID-je naprave, določi lahko tudi, ali je klic aktiven, in oddaljeno številko, s katero je klic povezan."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"branje natančnih stanj telefona"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Aplikaciji dovoli dostop do natančnih stanj telefona. To dovoljenje aplikaciji omogoča ugotoviti pravo stanje klica; ali je klic aktiven ali v ozadju; neuspele klice; natančno stanje podatkovne povezave in neuspele podatkovne povezave."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"preprečitev prehoda tabličnega računalnika v stanje pripravljenosti"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"preprečevanje prehoda v stanje pripravljenosti telefona"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Omogoča, da program prepreči prehod tabličnega računalnika v stanje pripravljenosti."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4a29310..fb12e96 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Омогућава апликацији да користи било који инсталирани декодер медија за декодирање за репродукцију."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"управљање поузданим акредитивима"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозвољава апликацији да инсталира и деинсталира CA сертификате као поуздане акредитиве."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"повезивање са неактивним услугама"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ова дозвола дозвољава систему Android да се веже за неактивне услуге апликације."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"покреће апликације током неактивности"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ова дозвола омогућава систему Android да покреће апликације у позадини док се уређај не користи."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"читање ресурса у власништву дијагностике и уписивање података у њих"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозвољава апликацији да чита и уписује податке у било који ресурс у власништву групе за дијагностиковање, на пример, датотеке у директоријуму /dev. То може да угрози стабилност и безбедност система и треба да је користе САМО произвођач или оператер у сврхе дијагностиковањa хардвера."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"омогућавање или онемогућавање компоненти апликације"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дозвољава апликацији да управља функцијама телефона на уређају. Апликација са овом дозволом може да прелази са једне мреже на другу и да без обавештења укључује и искључује радио телефона и сличне функције."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"читање статуса и идентитета телефона"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозвољава апликацији да приступа функцијама телефона на уређају. Ова дозвола омогућава апликацији да утврди број телефона и ИД-ове уређаја, затим да ли је позив активан, као и број даљинског уређаја са којим је успостављен позив."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"читај прецизне статусе телефона"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Омогућава апликацији да приступа прецизним статусима телефона. Ова дозвола омогућава апликацији да утврди стварни статус позива, да ли је позив активан или у позадини, неуспеле позиве, прецизан статус везе за пренос података и неуспела успостављања везе за пренос података."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"спречавање преласка таблета у стање спавања"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"спречавање преласка телефона у стање спавања"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозвољава апликацији да спречи таблет да пређе у стање спавања."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 09763b1..d6f7457 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Tillåter att appen använder installerade medieavkodare för att avkoda media för uppspelning."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"hantera betrodda uppgifter"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Tillåter att appen installerar och avinstallerar CA-certifikat som betrodda uppgifter."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"knyt till inaktiva tjänster"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Med den här behörigheten kan Android-systemet bindas till en apps inaktiva tjänster."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"kör appen när enheten är inaktiv"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Med den här behörigheten tillåts Android-systemet att köra appen i bakgrunden när enheten inte används."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"läsa/skriva till resurser som ägs av diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Tillåter att appen läser och skriver till en resurs som ägs av diag-gruppen, till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST användas av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"aktivera eller inaktivera appkomponenter"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Tillåter att appen styr enhetens telefonfunktioner. En app med den här behörigheten kan byta nätverk, aktivera/inaktivera mobilens radio och liknande utan att meddela dig."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"läsa telefonens status och identitet"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Tillåter att appen kommer åt enhetens telefonfunktioner. Med den här behörigheten tillåts appen att identifiera mobilens telefonnummer och enhets-ID, om ett samtal pågår och vilket nummer samtalet är kopplat till."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"läsa mobilens exakta status"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Tillåter att appen får tillgång till mobilens exakta status. Appen får behörighet att avgöra mobilens faktiska samtalsstatus, om samtalet är aktivt eller i bakgrunden, om samtal misslyckas, mobilens exakta dataanslutningsstatus och om dataanslutningar misslyckas."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"förhindra att surfplattan går in i viloläge"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"förhindra att telefonen sätts i viloläge"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Tillåter att appen förhindrar att surfplattan går in i viloläge."</string>
@@ -1459,7 +1461,7 @@
<string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Gränsen för data via Wi-Fi har överskridits"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> över angiven gräns."</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"Bakgrundsdata är begränsade"</string>
- <string name="data_usage_restricted_body" msgid="6741521330997452990">"Tryck för att radera begränsning"</string>
+ <string name="data_usage_restricted_body" msgid="6741521330997452990">"Tryck för att ta bort begränsning"</string>
<string name="ssl_certificate" msgid="6510040486049237639">"Säkerhetscertifikat"</string>
<string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Certifikatet är giltigt."</string>
<string name="issued_to" msgid="454239480274921032">"Utfärdad till:"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index e840e37..7f17c76 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -100,7 +100,7 @@
<string name="roamingText4" msgid="8808456682550796530">"Nje ya Jengo"</string>
<string name="roamingText5" msgid="7604063252850354350">"Urandaji - Mfumo unaopendelewa"</string>
<string name="roamingText6" msgid="2059440825782871513">"Uzururaji - Mfumo Unaopatikana"</string>
- <string name="roamingText7" msgid="7112078724097233605">"Uzururaji - Mwenza wa Ushirikiamo"</string>
+ <string name="roamingText7" msgid="7112078724097233605">"Roaming - Alliance Partner"</string>
<string name="roamingText8" msgid="5989569778604089291">"Uzururaji - Mwenzi wa Thamani"</string>
<string name="roamingText9" msgid="7969296811355152491">"Uzururaji - Utendajikazi Kamili wa Huduma"</string>
<string name="roamingText10" msgid="3992906999815316417">"Uzururaji - Utendajikazi Nusi wa Huduma"</string>
@@ -348,7 +348,7 @@
<string name="permlab_updateAppOpsStats" msgid="8829097373851521505">"rekebisha takwimu za oparesheni ya programu"</string>
<string name="permdesc_updateAppOpsStats" msgid="50784596594403483">"Inaruhusu programu kurekebisha takwimu za matumizi ya programu zilizokusanywa. Si ya kutumiwa na programu za kawaida."</string>
<string name="permlab_backup" msgid="470013022865453920">"Dhibiti kuhifadhi nakala na kurejesha kwa mfumo"</string>
- <string name="permdesc_backup" msgid="6912230525140589891">"Inaruhusu programu kudhibiti utaratibu wa kucheleza na kurejesha wa mfumo. Si kwa matumizi na programu za kawaida."</string>
+ <string name="permdesc_backup" msgid="6912230525140589891">"Huruhusu programu kudhibiti utaratibu wa kuhifadhi nakala rudufu na kurejesha mfumo. Haifai kutumiwa na programu za kawaida."</string>
<string name="permlab_confirm_full_backup" msgid="5557071325804469102">"thibitisha chelezo kamilifu au rejesha upya uendeshaji"</string>
<string name="permdesc_confirm_full_backup" msgid="1748762171637699562">"Huruhusu programu kuzindua kiolesura cha kuthibitisha kuhifadhiwa kwa nakala rudufu kamili. Haitumiwi na programu yoyote."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"onyesha madirisha yasiyoidhinishwa"</string>
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Huruhusu programu kutumia vyombo vyovyote vya habari vilivyosakinishwa ili kusimbua kwa ajili ya kucheza tena."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"dhibiti vitambulisho vinavyoaminika"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Huruhusu programu kusakinisha na kusanidua vyeti vya CA kama vitambulisho vinavyoaminika."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"funga kwenye huduma zisizofanya kitu"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Ruhusa hii huruhusu mfumo wa Android kuunga kwenye huduma za programu amabazo hazitumiki."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"endesha programu wakati kifaa hakifanyi kitu"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Ruhusa hii huwezesha mfumo wa Android kuendesha programu chini kwa chini wakati kifaa hakitumiki."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"soma/andika kwa vyanzo vinavyomilikiwa na diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Inaruhusu programu kusoma na kuandika kwa chanzo chochote kinachomilikiwa na kikundi cha diag; kwa mfano, faili katika /dev. Hii inaweza kuathiri udhabiti na usalama wa mfumo. Hii inapaswa kutumiwa TU kwa utambuzi mahsusi wa maunzi na mtengenezaji au opareta."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"wezesha au lemeza vijenzi vya programu"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Inaruhusu programu kudhibiti vipengee vya kifaa. Programu iliyo na ruhusa hii inaweza badilisha mtandao, kuzima na kuwasha redio ya simu bila hata kukujulisha."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"kusoma hali na kitambulisho cha simu"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Inaruhusu programu kufikia vipengele vya simu vya kifaa. Idhini hii inaruhusu programu kutambua nambari ya simu na kifaa, kama simu ni amilifu, na nambari ya mbali iliyounganishwa kwa simu."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"Soma hali sahihi ya simu"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Huruhusu programu kufikia hali sahihi ya simu. Ruhusa hii huwezesha programu kufahamu hali sahihi ya simu, iwapo simu inatumika au iko katika hali ya chini kwa chini, simu inaposhindikana, hali sahihi ya muunganisho wa data na muunganisho wa data unaposhindikana."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"zuia kompyuta ndogo dhidi ya kulala"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"kuzuia simu isilale"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Inaruhusu programu kuzuia kompyuta kibao kwenda kulala."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index c1f1c9b..f59b2d1 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"อนุญาตให้แอปพลิเคชันใช้ตัวถอดรหัสสื่อใดก็ได้ที่ติดตั้งไว้เพื่อถอดรหัสสำหรับการเล่น"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"จัดการข้อมูลรับรองที่เชื่อถือได้"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"อนุญาตให้แอปติดตั้งและถอนการติดตั้งใบรับรอง CA ในฐานะข้อมูลรับรองที่เชื่อถือได้"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"เชื่อมโยงกับบริการที่ไม่ได้ใช้งาน"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"สิทธิ์นี้จะทำให้ระบบแอนดรอยด์สามารถเชื่อมโยงกับบริการรายงานเวลาที่ไม่มีการใช้งานของแอปพลิเคชัน"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"เรียกใช้แอปพลิเคชันในระหว่างที่ไม่ได้ใช้งาน"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"สิทธิ์นี้ช่วยให้ระบบแอนดรอยด์สามารถเรียกใช้แอปพลิเคชันในพื้นหลังขณะไม่ได้ใช้งานอุปกรณ์อยู่"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"อ่าน/เขียนไปยังรีซอร์สที่เป็นเจ้าของโดยกลุ่มวินิจฉัย"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"อนุญาตให้แอปพลิเคชันอ่านและเขียนไปยังทรัพยากรที่เป็นของกลุ่มวินิจฉัย เช่น ไฟล์ใน /dev การทำเช่นนี้อาจส่งผลต่อความเสถียรและความปลอดภัยของระบบ และควรใช้สำหรับการวินิจฉัยเกี่ยวกับฮาร์ดแวร์โดยเฉพาะที่ทำโดยผู้ผลิตหรือผู้ให้บริการเท่านั้น"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"เปิดหรือปิดใช้งานคอมโพเนนต์ของแอปพลิเคชัน"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"อนุญาตให้แอปพลิชันควบคุมคุณลักษณะโทรศัพท์ของอุปกรณ์ แอปพลิเคชันที่ได้รับอนุญาตจะสามารถสลับเครือข่าย เปิดและปิดวิทยุในโทรศัพท์ และคุณลักษณะอื่นที่คล้ายกันนี้ได้โดยไม่ต้องแจ้งให้คุณทราบ"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"อ่านสถานะและข้อมูลระบุตัวตนของโทรศัพท์"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"อนุญาตให้แอปพลิเคชันเข้าถึงคุณลักษณะโทรศัพท์ของอุปกรณ์ การอนุญาตนี้ทำให้แอปพลิเคชันสามารถตรวจสอบหมายเลขโทรศัพท์และรหัสอุปกรณ์ ตรวจสอบว่ามีการโทรที่ทำงานอยู่หรือไม่ และตรวจสอบหมายเลขระยะไกลที่เชื่อมต่อด้วยการโทร"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"อ่านสถานะที่แม่นยำของโทรศัพท์"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"ช่วยให้แอปสามารถเข้าถึงสถานะที่แม่นยำของโทรศัพท์ สิทธิ์นี้ช่วยให้แอปสามารถทราบถึงสถานะการโทรที่แท้จริงว่ากำลังมีการโทรอยู่หรือการโทรในพื้นหลัง การโทรล้มเหลว สถานะการเชื่อมต่อข้อมูลที่แม่นยำและการเชื่อมต่อข้อมูลล้มเหลว"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ป้องกันไม่ให้โทรศัพท์เข้าโหมดสลีป"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"อนุญาตให้แอปพลิเคชันป้องกันไม่ให้แท็บเล็ตเข้าสู่โหมดสลีป"</string>
@@ -1361,7 +1363,7 @@
<string name="car_mode_disable_notification_message" msgid="8035230537563503262">"แตะเพื่อออกจากโหมดรถยนต์"</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"การปล่อยสัญญาณหรือฮอตสปอตทำงานอยู่"</string>
<string name="tethered_notification_message" msgid="6857031760103062982">"แตะเพื่อตั้งค่า"</string>
- <string name="back_button_label" msgid="2300470004503343439">"ย้อนกลับ"</string>
+ <string name="back_button_label" msgid="2300470004503343439">"กลับ"</string>
<string name="next_button_label" msgid="1080555104677992408">"ถัดไป"</string>
<string name="skip_button_label" msgid="1275362299471631819">"ข้าม"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"การใช้งานข้อมูลมือถือในระดับสูง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 4196a82..0f5f53c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Pinapayagan ang app na gumamit ng anumang naka-install na media decoder upang mag-decode para sa pag-playback."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"mga pinamamahalaang pinagkakatiwalaang kredensyal"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Pinapayagan ang app na mag-install at mag-uninstall ng mga CA certificate bilang mga pinagkakatiwalaang kredensyal."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"sumailalim sa mga idle na serbisyo"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Nagbibigay-daan ang pahintulot na ito sa Android system na sumailalim sa mga idle na serbisyo ng isang application."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"paganahin ang application habang idle"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Nagbibigay-daan ang pahintulot na ito sa Android system na paganahin ang application sa background habang hindi ginagamit ang device."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"magbasa/magsulat sa mga mapagkukunang pag-aari ng diag"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Pinapayagan ang app na magbasa at magsulat sa anumang mapagkukunang pag-aari ng pangkat ng diag; halimbawa, mga file sa /dev. Maaaring potensyal na maapektuhan nito ang katatagan at seguridad ng system. Dapat LAMANG itong gamitin para sa diagnostics na tukoy sa hardware ng tagagawa o operator."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"paganahin o huwag paganahin ang mga bahagi ng app"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Pinapayagan ang app na kontrolin ang mga tampok ng telepono ng device. Maaaring lumipat ng mga network ang isang app na mayroong ganitong pahintulot, i-on o i-off ang radyo ng telepono at mga kaparehong bagay nang hindi ka nano-notify."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"basahin ang katayuan at pagkakakilanlan ng telepono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Pinapayagan ang app na i-access ang mga tampok ng telepono ng device. Pinapayagan ng pahintulot na ito ang app na tukuyin ang numero ng telepono at mga ID ng device, kung aktibo man ang isang tawag, at ang malayuang numerong ikinonekta ng isang tawag."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"basahin ang tiyak na katayuan ng telepono"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Binibigyang-daan ang app na ma-access ang tumpak na katayuan ng telepono. Nagbibigay-daan ang pahintulot na ito sa app na matukoy ang tunay na status ng tawag, kung aktibo ang isang tawag o nasa background, mga hindi natuloy na tawag, tumpak na status ng koneksyon sa data at hindi natuloy na pagkonekta sa data."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"pigilan ang tablet mula sa pag-sleep"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"pigilan ang telepono mula sa paghinto"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Pinapayagan ang app na pigilan ang tablet mula sa pag-sleep."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 132d9f0..35b1241 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Uygulamaya, oynatma kodunu çözmek için herhangi bir yüklü medya kod çözücüyü kullanma izni verir."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"güvenilen kimlik bilgilerini yönetme"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Uygulamaya, güvenilir kimlik bilgileri olarak CA sertifikaları yükleme veya sertifikaların yüklemelerini kaldırma izni verir."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"boşta kalma hizmetlerine bağlan"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Bu izin, Android sistemin, bir uygulamanın boşta kalma hizmetlerine bağlanmasına olanak sağlar."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"boşta kaldığında uygulamayı çalıştır"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Bu izin, cihaz kullanımda değilken Android sistemin uygulamayı arka planda çalıştırmasına olanak sağlar."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"sahibi tanılama olan kaynakları oku/bunlara yaz"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Uygulamaya, tanılama grubunun sahip olduğu tüm kaynaklara (örneğin /dev içindeki dosyalar) okuma ve yazma izni verir. Bu işlevin sistem kararlılığını ve güvenliğini olumsuz etkileme olasılığı vardır. Üretici veya operatör tarafından YALNIZCA donanıma özgü tanılama için kullanılmalıdır."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"uygulama bileşenlerini etkinleştir veya devre dışı bırak"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Uygulamaya, cihazın telefon özelliklerini kontrol etme izni verir. Bu izne sahip bir uygulama sizi hiç uyarmadan ağlar arasında geçiş, telefonun radyosunu açıp kapatma ve benzeri işlemler yapabilir."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"telefonun durumunu ve kimliğini okuma"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Uygulamaya cihazdaki telefon özelliklerine erişme izni verir. Bu izin, uygulamanın telefon numarasını ve cihaz kimliğini, etkin bir çağrı olup olmadığını ve çağrıda bağlanılan karşı tarafın numarasını öğrenmesine olanak sağlar."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"telefon durum bilgilerini hassas bir şekilde oku"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Uygulamanın, telefonun durum bilgilerine hassas bir şekilde erişmesine izin verir. Bu izin sayesinde uygulama, gerçek çağrı durumunu, çağrının aktif mi yoksa arka planda mı olduğunu, çağrının başarısız olup olmadığını, veri bağlantısı durumuyla ilgili hassas bilgileri ve veri bağlantısının başarısız olup olmadığını belirleyebilir."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"tabletin uykuya geçmesini önle"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"telefonun uykuya geçmesini önleme"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Uygulamaya, tabletin uykuya geçmesini önleme izni verir."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 3922b0c..3a5f184 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Дозволяє програмі використовувати будь-який установлений медіа-декодер для декодування з метою відтворення."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"керувати захищеними обліковими даними"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Дозволяє програмі встановлювати та видаляти сертифікати центру сертифікації (CA) як захищені облікові дані."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"взаємодіяти з неактивними службами"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Такий дозвіл дає змогу системі Android прив’язуватися до неактивних служб програми."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"запускати додаток, коли пристрій неактивний"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Маючи цей дозвіл, система Android може запускати додаток у фоновому режимі, коли пристрій не використовується."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"чит./зап. на ресури., якими вол. діаг."</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Дозволяє програмі читати та писати на будь-який ресурс, яким володіє діагностична група; наприклад, у файли в папці /dev. Це потенційно може вплинути на стабільність і безпеку системи. Потрібно використовувати ЛИШЕ для певної діагностики обладнання, яку виконує виробник чи оператор."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"вмикати чи вимикати компоненти програми"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Дозволяє програмі контролювати телефонні функції пристрою. Програма з цим дозволом може переключати мережі, вмикати та вимикати радіо в телефоні тощо без вашого відома."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"читати статус та ідентифікаційну інформацію телефону"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Дозволяє програмі отримувати доступ до телефонних функцій пристрою. Такий дозвіл дає програмі змогу визначати номер телефону й ідентифікатори пристрою, активність виклику, а також віддалений номер, на який здійснюється виклик."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"читати точні статуси телефону"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Дозволяє додатку отримувати доступ до статусів телефону. Цей дозвіл дає додатку змогу визначати статус виклику (активний чи у фоновому режимі), помилки викликів, точний статус передавання даних і помилки передавання даних."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"не доп.перехід пристр.в реж.сну"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"недоп. перехід тел. в реж. сну"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Дозволяє програмі не допускати перехід планшетного ПК у режим сну."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e774e8e..4b5e48a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Cho phép ứng dụng sử dụng bất kỳ trình giải mã phương tiện nào đã cài đặt nhằm giải mã để phát lại."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"quản lý thông tin xác thực đáng tin cậy"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Cho phép ứng dụng cài đặt và gỡ cài đặt chứng chỉ CA dưới dạng thông tin xác thực đáng tin cậy."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"liên kết với dịch vụ không dùng đến"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Quyền này cho phép hệ thống Android liên kết với các dịch vụ ở trạng thái rảnh của ứng dụng."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"chạy ứng dụng trong thời gian rảnh"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Quyền này cho phép hệ thống Android chạy ứng dụng trong nền khi thiết bị không được sử dụng."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"đọc/ghi vào tài nguyên do chẩn đoán sở hữu"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Cho phép ứng dụng đọc và ghi vào bất kỳ tài nguyên nào do nhóm chẩn đoán sở hữu; ví dụ: các tệp trong /dev. Quyền này có thể ảnh hưởng đến sự ổn định và tính bảo mật của hệ thống. CHỈ nên sử dụng quyền này cho các chẩn đoán phần cứng cụ thể của nhà sản xuất hoặc nhà cung cấp."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"bật hoặc tắt cấu phần ứng dụng"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Cho phép ứng dụng kiểm soát các tính năng điện thoại của thiết bị. Ứng dụng có quyền này có thể chuyển đổi mạng, bật và tắt radio điện thoại cũng như thực hiện các tác vụ tương tự mà không cần thông báo cho bạn."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"đọc trạng thái và nhận dạng của điện thoại"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Cho phép ứng dụng truy cập vào các tính năng điện thoại của thiết bị. Quyền này cho phép ứng dụng xác định số điện thoại và ID thiết bị, cho dù cuộc gọi có hiện hoạt hay không và số từ xa có được kết nối bằng một cuộc gọi hay không."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"đọc trạng thái điện thoại chính xác"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Cho phép ứng dụng truy cập trạng thái điện thoại chính xác. Quyền này cho phép ứng dụng xác định trạng thái cuộc gọi thực, cuộc gọi đang hoạt động hay trong nền, cuộc gọi không thành công, trạng thái kết nối dữ liệu chính xác và kết nối dữ liệu không thành công."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"ngăn máy tính bảng chuyển sang chế độ ngủ"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ngăn điện thoại chuyển sang chế độ ngủ"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Cho phép ứng dụng ngăn máy tính bảng chuyển sang chế độ ngủ."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 035c5b6..ebf11c4 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -76,7 +76,7 @@
<string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"默认显示本机号码,在下一次通话中也显示"</string>
<string name="serviceNotProvisioned" msgid="8614830180508686666">"未提供服务。"</string>
<string name="CLIRPermanent" msgid="3377371145926835671">"您无法更改来电显示设置。"</string>
- <string name="RestrictedChangedTitle" msgid="5592189398956187498">"访问受限情况已发生变化"</string>
+ <string name="RestrictedChangedTitle" msgid="5592189398956187498">"网络可用情况发生变化"</string>
<string name="RestrictedOnData" msgid="8653794784690065540">"数据服务已禁用。"</string>
<string name="RestrictedOnEmergency" msgid="6581163779072833665">"紧急服务已禁用。"</string>
<string name="RestrictedOnNormal" msgid="4953867011389750673">"已禁用语音服务。"</string>
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允许该应用使用任何已安装的媒体解码器进行解码,以便播放媒体。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理受信任的凭据"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允许应用安装和卸载 CA 证书(作为受信任的凭据)。"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"绑定到闲置服务"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此权限允许Android系统绑定至应用的闲置服务。"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"在设备处于闲置状态时运行应用"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"当设备处于闲置状态时,此权限允许Android系统在后台运行该应用。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"读取/写入诊断所拥有的资源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允许应用读取/写入诊断组拥有的所有资源(例如 /dev 中的文件)。这可能会影响系统的稳定性和安全性。此权限仅供制造商或运营商诊断硬件方面的问题时使用。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"启用或停用应用组件"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允许应用控制设备的电话功能。拥有此权限的应用可在不通知您的情况下执行切换网络、开关手机无线装置等此类操作。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"读取手机状态和身份"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允许该应用访问设备的电话功能。此权限可让该应用确定本机号码和设备 ID、是否正处于通话状态以及拨打的号码。"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"读取确切的手机状态"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允许应用获取确切的手机状态。此权限可让应用确定实际通话状态、通话是在界面上进行还是在后台进行、通话未接通情况、确切的数据网络连接状态,以及数据网络连接失败情况。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"阻止平板电脑进入休眠状态"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手机休眠"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允许应用阻止平板电脑进入休眠状态。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 42aaf93..303affa 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器為播放解碼。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證為信任的憑證及解除安裝 CA 憑證。"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當您不使用裝置時,此權限允許 Android 系統在背景執行應用程式。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀取/寫入由診斷應用程式擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取及寫入診斷群組所擁有的任何資源 (例如:位於 /dev 中的檔案)。這可能會影響系統的穩定性及安全性,只應對製造商或網絡供應商所使用的硬件專用診斷程式開放這項權限。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允許應用程式控制裝置上的電話功能。具備此權限的應用程式可在未通知您的情況下,進行切換網絡以及開關手機無線電之類的操作。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限允許應用程式確定手機號碼和裝置編號、是否正在通話中,以及所撥打的對方號碼。"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"讀取精確的手機狀態"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允許應用程式存取精確的手機狀態。此權限可讓應用程式判斷實際的通話狀態、是否正在通話或在背景中運作、無法通話次數、精確的數據連線狀態和數據連線失敗次數。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入休眠狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 6c3f1c4..ad2f63c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"允許應用程式使用任何已安裝的媒體解碼器進行解碼以播放影片。"</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"管理信任的憑證"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"允許應用程式安裝 CA 憑證 (做為信任的憑證) 及解除安裝 CA 憑證。"</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"繫結至閒置服務"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"此權限允許 Android 系統繫結至應用程式的閒置服務。"</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"當裝置閒置時執行應用程式"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"當裝置處於未使用狀態時,此權限允許 Android 系統在背景執行應用程式。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"讀寫 diag 擁有的資源"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"允許應用程式讀取或寫入診斷群組擁有的任何資源,例如 /dev 底下的檔案。這可能會影響系統的穩定性和安全性,因此應由製造商或電信業者操作,且只用在特定硬體診斷。"</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"啟用或停用應用程式元件"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"允許應用程式控制裝置的電話功能。擁有這項權限的應用程式可在未通知您的情況下,任意切換網路、開啟或關閉手機無線電等。"</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"讀取手機狀態和識別碼"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"允許應用程式使用裝置的電話功能。這項權限可讓應用程式判讀手機號碼和裝置 ID、是否正在通話中,以及所撥打的對方號碼。"</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"讀取手機精確狀態"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"允許應用程式存取手機的精確狀態。這項權限可讓應用程式判別實際通話狀態,包括通話正在進行中或是在背景運作、通話失敗次數、精確數據連線狀態和數據連線失敗次數。"</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"防止平板電腦進入休眠狀態"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"防止手機進入待命狀態"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"允許應用程式防止平板電腦進入休眠狀態。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c897bdc..802fc0f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -423,8 +423,8 @@
<string name="permdesc_anyCodecForPlayback" msgid="8283912488433189010">"Ivumela uhlelo lokusebenza ukusebenzisa noma isiphi isiqophi semidiya esifakiwe ukuqopha ukudlala."</string>
<string name="permlab_manageCaCertificates" msgid="1678391896786882014">"phatha ukuqinisekisa okuthenjiwe"</string>
<string name="permdesc_manageCaCertificates" msgid="4015644047196937014">"Ivumela uhlelo lokusebenza ukuthi lifake liphinde likhiphe izitifiketi ze-CA njengokuqinisekiswa okuthenjiwe."</string>
- <string name="permlab_bindIdleService" msgid="7521398788076342815">"bophezela kumasevisi angenzi lutho"</string>
- <string name="permdesc_bindIdleService" msgid="7747505810143356528">"Le mvume ivumela isistimu ye-Android ukuthi ibophezeleke kumasevisi angenzi lutho wohlelo lokusebenza."</string>
+ <string name="permlab_bindIdleService" msgid="816311765497613780">"qalisa uhlelo lokusebenza ngesikhathi sokungenzi lutho"</string>
+ <string name="permdesc_bindIdleService" msgid="1767538493214100612">"Le mvume ivumela isistimu ye-Android ukuthi iqalise uhlelo lokusebenza ngemuva ngenkathi idivayisi ingasebenzi."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"funda/bhalela emithombweni ephethwe idayegi"</string>
<string name="permdesc_diagnostic" msgid="6608295692002452283">"Ivumela uhlelo lokusebenza ukufunda nokubhala kunoma yimuphi umthombo weqembu ledayegi; ngokwesibonelo, amafayela akwi/dev. Lokhu kungase kuthinte kakhulu ukuba nokuphepha kohlelo. Lokhu kumele kusebenziselwe KUPHELA ukuhlola ihadiwe okucacile ngumkhiqizi noma u-opheretha."</string>
<string name="permlab_changeComponentState" msgid="6335576775711095931">"vumela noma vimbela izingxenye zensiza"</string>
@@ -563,6 +563,8 @@
<string name="permdesc_modifyPhoneState" msgid="1029877529007686732">"Ivumela ukuthi uhlelo lokusebenza ilawule okuqukethwe ocingweni edivayisini. Insiza enalemvume ingaguquguqula amanethwekhi, ivule umsakazo wocingo iphinde iwucishe kanye nokunye okufana nalokho ngaphandle kokukwazisa."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"funda isimo sefoni kanye nesazisi"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Ivumela uhlelo lokusebenza ukufinyelela izici zefoni zedivayisi. Le mvume ivumela uhlelo lokusebenza ukucacisa inombolo yefoni nobunikazi bedivayisi, ukuthi noma ikholi iyasebenza, futhi nenombolo yesilawuli kude zixhunywe ngekholi."</string>
+ <string name="permlab_readPrecisePhoneState" msgid="5476483020282007597">"funda izimo zefoni ezinembile"</string>
+ <string name="permdesc_readPrecisePhoneState" msgid="6648009074263855418">"Ivumelanisa uhlelo lokusebenza ukuthi lufinyelele kuzimo ezinembile zefoni. Le mvume ivumela uhlelo lokusebenza ukuthi linqume isimo sekholi sangempela, noma ikholi isebenza noma ingemuva, ikholi ihluleka, isimo esinembile sokuxhumeka kwedatha nokuhluleka kokuxhumeka kwedatha."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"gwema ithebhulethi ukuba ingalali"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"gwema ifoni ukuba ingalali"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Ivumela uhlelo lokusebenza ukuthi linqande ithebulethi yakho ukuthi ilale."</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 95792ba..d1fa082 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -77,7 +77,8 @@
<item>@drawable/btn_default_disabled_focused_holo_dark</item>
<item>@drawable/btn_default_holo_dark</item>
<item>@drawable/btn_default_holo_light</item>
- <item>@drawable/btn_default_quantum</item>
+ <item>@drawable/btn_default_quantum_dark</item>
+ <item>@drawable/btn_default_quantum_light</item>
<item>@drawable/btn_star_off_normal_holo_light</item>
<item>@drawable/btn_star_on_normal_holo_light</item>
<item>@drawable/btn_star_on_disabled_holo_light</item>
@@ -135,7 +136,8 @@
<item>@drawable/expander_group_holo_light</item>
<item>@drawable/list_selector_holo_dark</item>
<item>@drawable/list_selector_holo_light</item>
- <item>@drawable/list_selector_quantum</item>
+ <item>@drawable/list_selector_quantum_light</item>
+ <item>@drawable/list_selector_quantum_dark</item>
<item>@drawable/list_section_divider_holo_light</item>
<item>@drawable/list_section_divider_holo_dark</item>
<item>@drawable/menu_hardkey_panel_holo_dark</item>
@@ -228,9 +230,11 @@
<item>@drawable/ic_clear</item>
<item>@drawable/ic_clear_disabled</item>
<item>@drawable/ic_clear_normal</item>
- <item>@drawable/ic_search</item>
+ <item>@drawable/ic_search_api_holo_dark</item>
+ <item>@drawable/ic_search_api_holo_light</item>
<item>@drawable/ic_go</item>
- <item>@drawable/ic_voice_search</item>
+ <item>@drawable/ic_voice_search_api_holo_dark</item>
+ <item>@drawable/ic_voice_search_api_holo_light</item>
<item>@drawable/dialog_bottom_holo_dark</item>
<item>@drawable/dialog_bottom_holo_light</item>
<item>@drawable/dialog_full_holo_dark</item>
@@ -259,7 +263,8 @@
<item>@drawable/ab_solid_shadow_holo</item>
<item>@drawable/item_background_holo_dark</item>
<item>@drawable/item_background_holo_light</item>
- <item>@drawable/item_background_quantum</item>
+ <item>@drawable/item_background_quantum_light</item>
+ <item>@drawable/item_background_quantum_dark</item>
<item>@drawable/fastscroll_thumb_holo</item>
<item>@drawable/fastscroll_thumb_pressed_holo</item>
<item>@drawable/fastscroll_thumb_default_holo</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a8ae47e..bfd7565 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2123,6 +2123,10 @@
<!-- scale of the view in the y direction. -->
<attr name="scaleY" format="float" />
+ <!-- Defines whether the View casts a shadow when it has a 3D rotation or Z
+ translation.-->
+ <attr name="castsShadow" format="boolean" />
+
<!-- Determines which side the vertical scroll bar should be placed on. -->
<attr name="verticalScrollbarPosition">
<!-- Place the scroll bar wherever the system default determines. -->
@@ -2257,6 +2261,14 @@
<attr name="sharedElementName" format="string" />
</declare-styleable>
+ <!-- Attributes that can be assigned to a tag for a particular View. -->
+ <declare-styleable name="ViewTag">
+ <!-- Specifies the key identifying a tag. This must be a resource reference. -->
+ <attr name="id" />
+ <!-- Specifies the value with which to tag the view. -->
+ <attr name="value" />
+ </declare-styleable>
+
<!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
of its subclasses. Also see {@link #ViewGroup_Layout} for
attributes that this class processes in its children. -->
@@ -4082,19 +4094,6 @@
RTL (right-to-left). See
{@link android.graphics.drawable.Drawable#setAutoMirrored}. -->
<attr name="autoMirrored" format="boolean" />
- <!-- If set, specifies the color to apply to the drawable as a color filter. By
- default, no color filter is applied. -->
- <attr name="colorFilterColor" format="color" />
- <!-- When a color filter color is set, specifies its Porter-Duff blending mode.
- The default value is multiply. -->
- <attr name="colorFilterMode">
- <!-- [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- </attr>
</declare-styleable>
<!-- Drawable used to render several states. Each state is represented by
@@ -4379,8 +4378,21 @@
<!-- Indicates if the drawable needs to be mirrored when its layout direction is
RTL (right-to-left). -->
<attr name="autoMirrored" />
- <attr name="colorFilterColor" />
- <attr name="colorFilterMode" />
+ <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+ no tint is applied. May be a color state list. -->
+ <attr name="tint" />
+ <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+ default value is src_in, which treats the drawable as an alpha mask. -->
+ <attr name="tintMode">
+ <!-- [Sa * Da, Sc * Da] -->
+ <enum name="src_in" value="0" />
+ <!-- [Da, Sc * Da + (1 - Sa) * Dc] -->
+ <enum name="src_atop" value="1" />
+ <!-- [Sa * Da, Sc * Dc] -->
+ <enum name="multiply" value="2" />
+ <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
+ <enum name="screen" value="3" />
+ </attr>
</declare-styleable>
<!-- Drawable used to draw 9-patches. -->
@@ -4394,8 +4406,12 @@
<!-- Indicates if the drawable needs to be mirrored when its layout direction is
RTL (right-to-left). -->
<attr name="autoMirrored" />
- <attr name="colorFilterColor" />
- <attr name="colorFilterMode" />
+ <!-- If set, specifies the color to apply to the drawable as a tint. By default,
+ no tint is applied. May be a color state list. -->
+ <attr name="tint" />
+ <!-- When a tint color is set, specifies its Porter-Duff blending mode. The
+ default value is src_in, which treats the drawable as an alpha mask. -->
+ <attr name="tintMode" />
</declare-styleable>
<!-- Drawable used to draw a single color. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b20f5ba..2efbca2 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -259,6 +259,17 @@
applications can request this feature. Default value is false. -->
<attr name="requiredForAllUsers" format="boolean" />
+ <!-- Flag to specifiy for which types of profile this application needs to be present.
+ Only pre-installed applications can request this feature. Default is none. -->
+ <attr name="requiredForProfile">
+ <!-- This application needs to be present for restricted profiles -->
+ <flag name="restricted" value="0x0001" />
+ <!-- This application needs to be present for managed profiles -->
+ <flag name="managed" value="0x0002" />
+ <!-- This application needs to be present for all types of profiles -->
+ <flag name="all" value="0xFFFF" />
+ </attr>
+
<!-- Flag indicating whether the application can be debugged, even when
running on a device that is running in user mode. -->
<attr name="debuggable" format="boolean" />
@@ -901,6 +912,7 @@
<attr name="hasCode" format="boolean" />
<attr name="persistent" />
<attr name="requiredForAllUsers" />
+ <attr name="requiredForProfile" />
<!-- Specify whether the components in this application are enabled or not (that is, can be
instantiated by the system).
If "false", it overrides any component specific values (a value of "true" will not
@@ -1777,6 +1789,16 @@
<attr name="publicKey" />
</declare-styleable>
+ <!-- Attributes relating to resource overlay packages. -->
+ <declare-styleable name="AndroidManifestResourceOverlay" parent="AndroidManifest">
+ <!-- Package name of base package whose resources will be overlaid. -->
+ <attr name="targetPackage" />
+
+ <!-- Load order of overlay package. -->
+ <attr name="priority" />
+
+ </declare-styleable>
+
<!-- Declaration of an {@link android.content.Intent} object in XML. May
also include zero or more {@link #IntentCategory <category> and
{@link #Extra <extra>} tags. -->
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index 10a5d85..18e4f2f 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -26,5 +26,4 @@
<bool name="show_ongoing_ime_switcher">true</bool>
<bool name="action_bar_expanded_action_views_exclusive">true</bool>
<bool name="target_honeycomb_needs_options_menu">true</bool>
- <bool name="flip_controller_fallback_keys">false</bool>
</resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 55babfa..1947c50 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -123,8 +123,8 @@
<color name="facelock_spotlight_mask">#CC000000</color>
<!-- For holo theme -->
- <drawable name="screen_background_holo_light">#fff3f3f3</drawable>
- <drawable name="screen_background_holo_dark">#ff000000</drawable>
+ <drawable name="screen_background_holo_light">#fff3f3f3</drawable>
+ <drawable name="screen_background_holo_dark">#ff000000</drawable>
<color name="background_holo_dark">#ff000000</color>
<color name="background_holo_light">#fff3f3f3</color>
<color name="bright_foreground_holo_dark">@android:color/background_holo_light</color>
diff --git a/core/res/res/values/colors_quantum.xml b/core/res/res/values/colors_quantum.xml
new file mode 100644
index 0000000..b623263
--- /dev/null
+++ b/core/res/res/values/colors_quantum.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <color name="background_quantum_dark">#ff000000</color>
+ <color name="background_quantum_light">#fff3f3f3</color>
+
+ <color name="bright_foreground_quantum_dark">@color/background_quantum_light</color>
+ <color name="bright_foreground_quantum_light">@color/background_quantum_dark</color>
+ <color name="bright_foreground_disabled_quantum_dark">#ff4c4c4c</color>
+ <color name="bright_foreground_disabled_quantum_light">#ffb2b2b2</color>
+ <color name="bright_foreground_inverse_quantum_dark">@color/bright_foreground_quantum_light</color>
+ <color name="bright_foreground_inverse_quantum_light">@color/bright_foreground_quantum_dark</color>
+
+ <color name="dim_foreground_quantum_dark">#bebebe</color>
+ <color name="dim_foreground_quantum_light">#323232</color>
+ <color name="dim_foreground_disabled_quantum_dark">#80bebebe</color>
+ <color name="dim_foreground_disabled_quantum_light">#80323232</color>
+
+ <color name="hint_foreground_quantum_dark">#808080</color>
+ <color name="hint_foreground_quantum_light">#808080</color>
+ <color name="highlighted_text_quantum_dark">#6633b5e5</color>
+ <color name="highlighted_text_quantum_light">#6633b5e5</color>
+
+ <color name="timepicker_default_background_quantum_dark">#ff303030</color>
+ <color name="timepicker_default_background_quantum_light">@color/white</color>
+ <color name="timepicker_default_text_color_quantum_dark">@color/white</color>
+ <color name="timepicker_default_text_color_quantum_light">#8c8c8c</color>
+ <color name="timepicker_default_disabled_color_quantum_dark">#7f08c8c8</color>
+ <color name="timepicker_default_disabled_color_quantum_light">#7f000000</color>
+ <color name="timepicker_default_ampm_selected_background_color_quantum_dark">@color/holo_blue_light</color>
+ <color name="timepicker_default_ampm_selected_background_color_quantum_light">@color/holo_blue_light</color>
+ <color name="timepicker_default_ampm_unselected_background_color_quantum_dark">@color/transparent</color>
+ <color name="timepicker_default_ampm_unselected_background_color_quantum_light">@color/white</color>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b1b1f42..8d68277 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -658,6 +658,11 @@
Must be in the range specified by minimum and maximum. -->
<integer name="config_screenBrightnessSettingDefault">102</integer>
+ <!-- Screen brightness used to dim the screen while dozing in a very low power state.
+ May be less than the minimum allowed brightness setting
+ that can be set by the user. -->
+ <integer name="config_screenBrightnessDoze">1</integer>
+
<!-- Screen brightness used to dim the screen when the user activity
timeout expires. May be less than the minimum allowed brightness setting
that can be set by the user. -->
@@ -1078,8 +1083,16 @@
<!-- Name of the wimax state tracker clas -->
<string name="config_wimaxStateTrackerClassname" translatable="false"></string>
- <!-- Is the dreams feature supported? -->
+ <!-- Specifies whether the dreams feature should be supported.
+ When true, the system will allow the user to configure dreams (screensavers)
+ to launch when a user activity timeout occurs or the system is told to nap.
+ When false, the dreams feature will be disabled (this does not affect dozing).
+
+ Consider setting this resource to false or disabling dreams by default when a
+ doze component is specified below since dreaming will supercede dozing and
+ will prevent the system from entering a low power state until the dream ends. -->
<bool name="config_dreamsSupported">true</bool>
+
<!-- If supported, are dreams enabled? (by default) -->
<bool name="config_dreamsEnabledByDefault">true</bool>
<!-- If supported and enabled, are dreams activated when docked? (by default) -->
@@ -1089,6 +1102,70 @@
<!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
<string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+ <!-- Are we allowed to dream while not plugged in? -->
+ <bool name="config_dreamsEnabledOnBattery">false</bool>
+ <!-- Minimum battery level to allow dreaming when powered.
+ Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelMinimumWhenPowered">-1</integer>
+ <!-- Minimum battery level to allow dreaming when not powered.
+ Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelMinimumWhenNotPowered">15</integer>
+ <!-- If the battery level drops by this percentage and the user activity timeout
+ has expired, then assume the device is receiving insufficient current to charge
+ effectively and terminate the dream. Use -1 to disable this safety feature. -->
+ <integer name="config_dreamsBatteryLevelDrainCutoff">5</integer>
+
+ <!-- ComponentName of a dream to show whenever the system would otherwise have
+ gone to sleep. When the PowerManager is asked to go to sleep, it will instead
+ try to start this dream if possible. The dream should typically call startDozing()
+ to put the display into a low power state and allow the application processor
+ to be suspended. When the dream ends, the system will go to sleep as usual.
+ Specify the component name (Settings.Secure.SCREENSAVER_COMPONENT) or an
+ empty string if none.
+
+ Note that doze dreams are not subject to the same start conditions as ordinary dreams.
+ Doze dreams will run whenever the power manager is in a dozing state. -->
+ <string name="config_dozeComponent"></string>
+
+ <!-- Power Management: Specifies whether to decouple the auto-suspend state of the
+ device from the display on/off state.
+
+ When false, autosuspend_disable() will be called before the display is turned on
+ and autosuspend_enable() will be called after the display is turned off.
+ This mode provides best compatibility for devices using legacy power management
+ features such as early suspend / late resume.
+
+ When true, autosuspend_display() and autosuspend_enable() will be called
+ independently of whether the display is being turned on or off. This mode
+ enables the power manager to suspend the application processor while the
+ display is on.
+
+ This resource should be set to "true" when a doze component has been specified
+ to maximize power savings but not all devices support it.
+
+ Refer to autosuspend.h for details.
+ -->
+ <bool name="config_powerDecoupleAutoSuspendModeFromDisplay">false</bool>
+
+ <!-- Power Management: Specifies whether to decouple the interactive state of the
+ device from the display on/off state.
+
+ When false, setInteractive(..., true) will be called before the display is turned on
+ and setInteractive(..., false) will be called after the display is turned off.
+ This mode provides best compatibility for devices that expect the interactive
+ state to be tied to the display state.
+
+ When true, setInteractive(...) will be called independently of whether the display
+ is being turned on or off. This mode enables the power manager to reduce
+ clocks and disable the touch controller while the display is on.
+
+ This resource should be set to "true" when a doze component has been specified
+ to maximize power savings but not all devices support it.
+
+ Refer to power.h for details.
+ -->
+ <bool name="config_powerDecoupleInteractiveModeFromDisplay">false</bool>
+
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
@@ -1112,6 +1189,8 @@
<!-- Maximum number of supported users -->
<integer name="config_multiuserMaximumUsers">1</integer>
+ <!-- Whether UI for multi user should be shown -->
+ <bool name="config_enableMultiUserUI">false</bool>
<!-- Minimum span needed to begin a touch scaling gesture.
If the span is equal to or greater than this size, a scaling gesture
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 722f965..c814d25 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2097,8 +2097,7 @@
<public type="attr" name="windowContentTransitions" />
<public type="attr" name="windowContentTransitionManager" />
<public type="attr" name="translationZ" />
- <public type="attr" name="colorFilterColor" />
- <public type="attr" name="colorFilterMode" />
+ <public type="attr" name="tintMode" />
<public type="attr" name="isolatedZVolume" />
<public type="attr" name="controlX1" />
<public type="attr" name="controlY1" />
@@ -2108,6 +2107,8 @@
<public type="attr" name="toSceneName" />
<public type="attr" name="sharedElementName" />
<public type="attr" name="transitionGroup" />
+ <public type="attr" name="castsShadow" />
+ <public type="attr" name="requiredForProfile"/>
<public type="id" name="shared_element_name" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d70ce0a..91bef50 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1175,10 +1175,14 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
<string name="permdesc_manageCaCertificates">Allows the app to install and uninstall CA certificates as trusted credentials.</string>
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_bindIdleService">bind to idle services</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_bindIdleService">This permission allows the Android system to bind to an application\'s idle services.</string>
+ <!-- Title of a permission that is never presented to the user. This is not a
+ permission that an application must be granted by the user. Instead, it
+ is part of a mechanism that applications use to indicate to the system
+ that they want to do occasional work while the device is idle. -->
+ <string name="permlab_bindIdleService">run application during idle time</string>
+ <!-- Description of an application permission, so that the user can understand
+ what is being done if they are curious. -->
+ <string name="permdesc_bindIdleService">This permission allows the Android system to run the application in the background while the device is not in use.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_diagnostic">read/write to resources owned by diag</string>
@@ -1654,6 +1658,14 @@
connected by a call.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_readPrecisePhoneState">read precise phone states</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_readPrecisePhoneState">Allows the app to access the precise
+ phone states. This permission allows the app to determine the real
+ call status, whether a call is active or in the background, call fails,
+ precise data connection status and data connection fails.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_wakeLock" product="default">prevent phone from sleeping</string>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index cbf11cf..df850a7 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -33,57 +33,57 @@
<eat-comment />
<style name="Preference.Quantum">
- <item name="android:layout">@android:layout/preference_holo</item>
+ <item name="layout">@layout/preference_holo</item>
</style>
<style name="PreferenceFragment.Quantum">
- <item name="android:paddingStart">@dimen/preference_fragment_padding_side</item>
- <item name="android:paddingEnd">@dimen/preference_fragment_padding_side</item>
+ <item name="paddingStart">@dimen/preference_fragment_padding_side</item>
+ <item name="paddingEnd">@dimen/preference_fragment_padding_side</item>
</style>
<style name="Preference.Quantum.Information">
- <item name="android:layout">@android:layout/preference_information_holo</item>
- <item name="android:enabled">false</item>
- <item name="android:shouldDisableView">false</item>
+ <item name="layout">@layout/preference_information_holo</item>
+ <item name="enabled">false</item>
+ <item name="shouldDisableView">false</item>
</style>
<style name="Preference.Quantum.Category">
- <item name="android:layout">@android:layout/preference_category_holo</item>
+ <item name="layout">@layout/preference_category_holo</item>
<!-- The title should not dim if the category is disabled, instead only the preference children should dim. -->
- <item name="android:shouldDisableView">false</item>
- <item name="android:selectable">false</item>
+ <item name="shouldDisableView">false</item>
+ <item name="selectable">false</item>
</style>
<style name="Preference.Quantum.CheckBoxPreference">
- <item name="android:widgetLayout">@android:layout/preference_widget_checkbox</item>
+ <item name="widgetLayout">@layout/preference_widget_checkbox</item>
</style>
<style name="Preference.Quantum.SwitchPreference">
- <item name="android:widgetLayout">@android:layout/preference_widget_switch</item>
- <item name="android:switchTextOn">@android:string/capital_on</item>
- <item name="android:switchTextOff">@android:string/capital_off</item>
+ <item name="widgetLayout">@layout/preference_widget_switch</item>
+ <item name="switchTextOn">@string/capital_on</item>
+ <item name="switchTextOff">@string/capital_off</item>
</style>
<style name="Preference.Quantum.PreferenceScreen"/>
<style name="Preference.Quantum.DialogPreference">
- <item name="android:positiveButtonText">@android:string/ok</item>
- <item name="android:negativeButtonText">@android:string/cancel</item>
+ <item name="positiveButtonText">@string/ok</item>
+ <item name="negativeButtonText">@string/cancel</item>
</style>
<style name="Preference.Quantum.DialogPreference.YesNoPreference">
- <item name="android:positiveButtonText">@android:string/yes</item>
- <item name="android:negativeButtonText">@android:string/no</item>
+ <item name="positiveButtonText">@string/yes</item>
+ <item name="negativeButtonText">@string/no</item>
</style>
<style name="Preference.Quantum.DialogPreference.EditTextPreference">
- <item name="android:dialogLayout">@android:layout/preference_dialog_edittext</item>
+ <item name="dialogLayout">@layout/preference_dialog_edittext</item>
</style>
<style name="Preference.Quantum.RingtonePreference">
- <item name="android:ringtoneType">ringtone</item>
- <item name="android:showSilent">true</item>
- <item name="android:showDefault">true</item>
+ <item name="ringtoneType">ringtone</item>
+ <item name="showSilent">true</item>
+ <item name="showDefault">true</item>
</style>
<!-- Begin Quantum theme styles -->
@@ -92,10 +92,10 @@
<style name="TextAppearance.Quantum" parent="TextAppearance"/>
<style name="TextAppearance.Quantum.Inverse" parent="TextAppearance.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Large" parent="TextAppearance.Large"/>
@@ -105,183 +105,183 @@
<style name="TextAppearance.Quantum.Small" parent="TextAppearance.Small"/>
<style name="TextAppearance.Quantum.Large.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Medium.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Small.Inverse">
- <item name="android:textColor">?textColorSecondaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorSecondaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.SearchResult">
- <item name="android:textStyle">normal</item>
- <item name="android:textColor">?textColorPrimary</item>
- <item name="android:textColorHint">?textColorHint</item>
+ <item name="textStyle">normal</item>
+ <item name="textColor">?textColorPrimary</item>
+ <item name="textColorHint">?textColorHint</item>
</style>
<style name="TextAppearance.Quantum.SearchResult.Title">
- <item name="android:textSize">18sp</item>
+ <item name="textSize">18sp</item>
</style>
<style name="TextAppearance.Quantum.SearchResult.Subtitle">
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">?textColorSecondary</item>
+ <item name="textSize">14sp</item>
+ <item name="textColor">?textColorSecondary</item>
</style>
<style name="TextAppearance.Quantum.Widget" parent="TextAppearance.Widget"/>
<style name="TextAppearance.Quantum.Widget.Button" parent="TextAppearance.Quantum.Small.Inverse">
- <item name="android:textColor">@android:color/primary_text_light_nodisable</item>
+ <item name="textColor">@color/primary_text_light_nodisable</item>
</style>
<style name="TextAppearance.Quantum.Widget.IconMenu.Item" parent="TextAppearance.Quantum.Small">
- <item name="android:textColor">?textColorPrimary</item>
+ <item name="textColor">?textColorPrimary</item>
</style>
<!-- This style is for smaller screens; values-xlarge defines a version
for larger screens. -->
<style name="TextAppearance.Quantum.Widget.TabWidget">
- <item name="android:textSize">14sp</item>
- <item name="android:textStyle">normal</item>
- <item name="android:textColor">@android:color/tab_indicator_text</item>
+ <item name="textSize">14sp</item>
+ <item name="textStyle">normal</item>
+ <item name="textColor">@color/tab_indicator_text</item>
</style>
<style name="TextAppearance.Quantum.Widget.TextView">
- <item name="android:textColor">?textColorPrimaryDisableOnly</item>
- <item name="android:textColorHint">?textColorHint</item>
+ <item name="textColor">?textColorPrimaryDisableOnly</item>
+ <item name="textColorHint">?textColorHint</item>
</style>
<style name="TextAppearance.Quantum.Widget.TextView.PopupMenu">
- <item name="android:textSize">18sp</item>
- <item name="android:textColor">?textColorPrimaryDisableOnly</item>
- <item name="android:textColorHint">?textColorHint</item>
+ <item name="textSize">18sp</item>
+ <item name="textColor">?textColorPrimaryDisableOnly</item>
+ <item name="textColorHint">?textColorHint</item>
</style>
<style name="TextAppearance.Quantum.Widget.DropDownHint">
- <item name="android:textColor">?textColorPrimary</item>
- <item name="android:textSize">14sp</item>
+ <item name="textColor">?textColorPrimary</item>
+ <item name="textSize">14sp</item>
</style>
<style name="TextAppearance.Quantum.Widget.DropDownItem">
- <item name="android:textColor">?textColorPrimaryDisableOnly</item>
+ <item name="textColor">?textColorPrimaryDisableOnly</item>
</style>
<style name="TextAppearance.Quantum.Widget.TextView.SpinnerItem">
- <item name="android:textColor">?textColorPrimaryDisableOnly</item>
+ <item name="textColor">?textColorPrimaryDisableOnly</item>
</style>
<style name="TextAppearance.Quantum.Widget.EditText">
- <item name="android:textColor">@android:color/bright_foreground_light</item>
- <item name="android:textColorHint">@android:color/hint_foreground_holo_light</item>
+ <item name="textColor">@color/bright_foreground_light</item>
+ <item name="textColorHint">@color/hint_foreground_quantum_light</item>
</style>
<style name="TextAppearance.Quantum.Widget.PopupMenu" parent="TextAppearance.Widget.PopupMenu">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="textColor">?attr/textColorPrimary</item>
</style>
<style name="TextAppearance.Quantum.Widget.PopupMenu.Large">
- <item name="android:textSize">18sp</item>
+ <item name="textSize">18sp</item>
</style>
<style name="TextAppearance.Quantum.Widget.PopupMenu.Small">
- <item name="android:textSize">14sp</item>
+ <item name="textSize">14sp</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionBar.Title"
parent="TextAppearance.Quantum.Medium">
- <item name="android:textSize">@android:dimen/action_bar_title_text_size</item>
+ <item name="textSize">@dimen/action_bar_title_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionBar.Subtitle"
parent="TextAppearance.Quantum.Small">
- <item name="android:textSize">@android:dimen/action_bar_subtitle_text_size</item>
+ <item name="textSize">@dimen/action_bar_subtitle_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionBar.Title.Inverse"
parent="TextAppearance.Quantum.Medium.Inverse">
- <item name="android:textSize">@android:dimen/action_bar_title_text_size</item>
+ <item name="textSize">@dimen/action_bar_title_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse"
parent="TextAppearance.Quantum.Small.Inverse">
- <item name="android:textSize">@android:dimen/action_bar_subtitle_text_size</item>
+ <item name="textSize">@dimen/action_bar_subtitle_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionBar.Menu"
parent="TextAppearance.Quantum.Small">
- <item name="android:textSize">12sp</item>
- <item name="android:textStyle">bold</item>
- <item name="android:textColor">?android:attr/actionMenuTextColor</item>
- <item name="android:textAllCaps">@android:bool/config_actionMenuItemAllCaps</item>
+ <item name="textSize">12sp</item>
+ <item name="textStyle">bold</item>
+ <item name="textColor">?attr/actionMenuTextColor</item>
+ <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionMode"/>
<style name="TextAppearance.Quantum.Widget.ActionMode.Title"
parent="TextAppearance.Quantum.Medium">
- <item name="android:textSize">@android:dimen/action_bar_title_text_size</item>
+ <item name="textSize">@dimen/action_bar_title_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionMode.Subtitle"
parent="TextAppearance.Quantum.Small">
- <item name="android:textSize">@android:dimen/action_bar_subtitle_text_size</item>
+ <item name="textSize">@dimen/action_bar_subtitle_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionMode.Title.Inverse"
parent="TextAppearance.Quantum.Medium.Inverse">
- <item name="android:textSize">@android:dimen/action_bar_title_text_size</item>
+ <item name="textSize">@dimen/action_bar_title_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse"
parent="TextAppearance.Quantum.Small.Inverse">
- <item name="android:textSize">@android:dimen/action_bar_subtitle_text_size</item>
+ <item name="textSize">@dimen/action_bar_subtitle_text_size</item>
</style>
<style name="TextAppearance.Quantum.Widget.Switch" parent="TextAppearance.Quantum.Small">
<!-- Switch thumb asset presents a dark background. -->
- <item name="android:textColor">@android:color/secondary_text_holo_dark</item>
+ <item name="textColor">@color/secondary_text_quantum_dark</item>
</style>
<style name="TextAppearance.Quantum.Light.Widget.Switch" parent="TextAppearance.Quantum.Small">
<!-- Switch thumb asset presents a dark background. -->
- <item name="android:textColor">@android:color/primary_text_holo_dark</item>
+ <item name="textColor">@color/primary_text_quantum_dark</item>
</style>
<style name="TextAppearance.Quantum.WindowTitle">
- <item name="android:textColor">#fff</item>
- <item name="android:textSize">14sp</item>
- <item name="android:textStyle">bold</item>
+ <item name="textColor">#fff</item>
+ <item name="textSize">14sp</item>
+ <item name="textStyle">bold</item>
</style>
<style name="TextAppearance.Quantum.DialogWindowTitle">
- <item name="android:textSize">22sp</item>
- <item name="android:textColor">@android:color/holo_blue_light</item>
+ <item name="textSize">22sp</item>
+ <item name="textColor">@color/holo_blue_light</item>
</style>
<style name="TextAppearance.Quantum.CalendarViewWeekDayView" parent="TextAppearance.Small.CalendarViewWeekDayView">
- <item name="android:textColor">#505050</item>
+ <item name="textColor">#505050</item>
</style>
<!-- Light text styles -->
<style name="TextAppearance.Quantum.Light" parent="TextAppearance.Quantum"/>
<style name="TextAppearance.Quantum.Light.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Light.Large" parent="TextAppearance.Quantum.Large"/>
@@ -291,38 +291,38 @@
<style name="TextAppearance.Quantum.Light.Small" parent="TextAppearance.Quantum.Small"/>
<style name="TextAppearance.Quantum.Light.Large.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Light.Medium.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Light.Small.Inverse">
- <item name="android:textColor">?textColorPrimaryInverse</item>
- <item name="android:textColorHint">?textColorHintInverse</item>
- <item name="android:textColorHighlight">?textColorHighlightInverse</item>
- <item name="android:textColorLink">?textColorLinkInverse</item>
+ <item name="textColor">?textColorPrimaryInverse</item>
+ <item name="textColorHint">?textColorHintInverse</item>
+ <item name="textColorHighlight">?textColorHighlightInverse</item>
+ <item name="textColorLink">?textColorLinkInverse</item>
</style>
<style name="TextAppearance.Quantum.Light.SearchResult" parent="TextAppearance.Quantum.SearchResult">
- <item name="android:textColor">?textColorPrimary</item>
- <item name="android:textColorHint">?textColorHint</item>
+ <item name="textColor">?textColorPrimary</item>
+ <item name="textColorHint">?textColorHint</item>
</style>
<style name="TextAppearance.Quantum.Light.SearchResult.Title">
- <item name="android:textSize">18sp</item>
+ <item name="textSize">18sp</item>
</style>
<style name="TextAppearance.Quantum.Light.SearchResult.Subtitle">
- <item name="android:textSize">14sp</item>
- <item name="android:textColor">?textColorSecondary</item>
+ <item name="textSize">14sp</item>
+ <item name="textColor">?textColorSecondary</item>
</style>
<style name="TextAppearance.Quantum.Light.Widget" parent="TextAppearance.Widget"/>
@@ -330,8 +330,8 @@
<style name="TextAppearance.Quantum.Light.Widget.Button"/>
<style name="TextAppearance.Quantum.Light.Widget.EditText">
- <item name="android:textColor">@android:color/bright_foreground_dark</item>
- <item name="android:textColorHint">@android:color/hint_foreground_holo_dark</item>
+ <item name="textColor">@color/bright_foreground_dark</item>
+ <item name="textColorHint">@color/hint_foreground_quantum_dark</item>
</style>
<style name="TextAppearance.Quantum.Light.Widget.PopupMenu" parent="TextAppearance.Quantum.Widget.PopupMenu"/>
@@ -347,14 +347,14 @@
<style name="TextAppearance.Quantum.Light.Widget.ActionMode.Subtitle" parent="TextAppearance.Widget.ActionMode.Subtitle"/>
<style name="TextAppearance.Quantum.Light.WindowTitle">
- <item name="android:textColor">#fff</item>
- <item name="android:textSize">14sp</item>
- <item name="android:textStyle">bold</item>
+ <item name="textColor">#fff</item>
+ <item name="textSize">14sp</item>
+ <item name="textStyle">bold</item>
</style>
<style name="TextAppearance.Quantum.Light.DialogWindowTitle">
- <item name="android:textSize">22sp</item>
- <item name="android:textColor">@android:color/holo_blue_light</item>
+ <item name="textSize">22sp</item>
+ <item name="textColor">@color/holo_blue_light</item>
</style>
<style name="TextAppearance.Quantum.Light.CalendarViewWeekDayView" parent="TextAppearance.Small.CalendarViewWeekDayView"/>
@@ -367,67 +367,67 @@
<style name="Quantum.Light" />
<style name="Widget.Quantum.Button" parent="Widget.Button">
- <item name="android:background">@android:drawable/btn_default_holo_dark</item>
- <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
- <item name="android:textColor">@android:color/primary_text_holo_dark</item>
- <item name="android:minHeight">48dip</item>
- <item name="android:minWidth">64dip</item>
+ <item name="background">@drawable/btn_default_quantum_dark</item>
+ <item name="textAppearance">?attr/textAppearanceMedium</item>
+ <item name="textColor">@color/primary_text_quantum_dark</item>
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">64dip</item>
</style>
<style name="Widget.Quantum.StackView">
- <item name="android:resOutColor">@android:color/holo_blue_light</item>
- <item name="android:clickColor">@android:color/holo_blue_light</item>
+ <item name="resOutColor">@color/holo_blue_light</item>
+ <item name="clickColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Quantum.Button.Borderless">
- <item name="android:background">?android:attr/selectableItemBackground</item>
- <item name="android:paddingStart">4dip</item>
- <item name="android:paddingEnd">4dip</item>
+ <item name="background">?attr/selectableItemBackground</item>
+ <item name="paddingStart">4dip</item>
+ <item name="paddingEnd">4dip</item>
</style>
<style name="Widget.Quantum.Button.Borderless.Small">
- <item name="android:textSize">14sp</item>
+ <item name="textSize">14sp</item>
</style>
<style name="Widget.Quantum.Button.Small">
- <item name="android:background">@android:drawable/btn_default_holo_dark</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">@android:color/primary_text_holo_dark</item>
- <item name="android:minHeight">48dip</item>
- <item name="android:minWidth">48dip</item>
+ <item name="background">@drawable/btn_default_quantum_dark</item>
+ <item name="textAppearance">?attr/textAppearanceSmall</item>
+ <item name="textColor">@color/primary_text_quantum_dark</item>
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">48dip</item>
</style>
<style name="Widget.Quantum.Button.Inset">
- <item name="android:background">@android:drawable/button_inset</item>
+ <item name="background">@drawable/button_inset</item>
</style>
<style name="Widget.Quantum.Button.Toggle">
- <item name="android:background">@android:drawable/btn_toggle_holo_dark</item>
- <item name="android:textOn">@android:string/capital_on</item>
- <item name="android:textOff">@android:string/capital_off</item>
- <item name="android:disabledAlpha">?android:attr/disabledAlpha</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:minHeight">48dip</item>
+ <item name="background">@drawable/btn_toggle_holo_dark</item>
+ <item name="textOn">@string/capital_on</item>
+ <item name="textOff">@string/capital_off</item>
+ <item name="disabledAlpha">?attr/disabledAlpha</item>
+ <item name="textAppearance">?attr/textAppearanceSmall</item>
+ <item name="minHeight">48dip</item>
</style>
<style name="Quantum.ButtonBar" parent="ButtonBar">
- <item name="android:paddingTop">0dip</item>
- <item name="android:paddingStart">0dip</item>
- <item name="android:paddingEnd">0dip</item>
- <item name="android:paddingBottom">0dip</item>
- <item name="divider">?android:attr/dividerVertical</item>
+ <item name="paddingTop">0dip</item>
+ <item name="paddingStart">0dip</item>
+ <item name="paddingEnd">0dip</item>
+ <item name="paddingBottom">0dip</item>
+ <item name="divider">?attr/dividerVertical</item>
<item name="showDividers">middle</item>
<item name="dividerPadding">12dip</item>
<item name="background">@null</item>
</style>
<style name="Quantum.SegmentedButton" parent="SegmentedButton">
- <item name="android:background">@android:drawable/btn_group_holo_dark</item>
+ <item name="background">@drawable/btn_group_holo_dark</item>
</style>
<style name="Quantum.ButtonBar.AlertDialog">
- <item name="android:background">@null</item>
- <item name="android:dividerPadding">0dp</item>
+ <item name="background">@null</item>
+ <item name="dividerPadding">0dp</item>
</style>
<style name="Widget.Quantum.TextView" parent="Widget.TextView"/>
@@ -435,8 +435,8 @@
<style name="Widget.Quantum.CheckedTextView" parent="Widget.CheckedTextView"/>
<style name="Widget.Quantum.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
- <item name="android:background">@android:drawable/list_section_divider_holo_dark</item>
- <item name="android:textAllCaps">true</item>
+ <item name="background">@drawable/list_section_divider_holo_dark</item>
+ <item name="textAllCaps">true</item>
</style>
<style name="Widget.Quantum.TextSelectHandle" parent="Widget.TextSelectHandle"/>
@@ -446,8 +446,8 @@
<style name="Widget.Quantum.AbsListView" parent="Widget.AbsListView"/>
<style name="Widget.Quantum.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="android:dropDownSelector">@android:drawable/list_selector_holo_dark</item>
- <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum_dark</item>
+ <item name="popupBackground">@drawable/menu_dropdown_panel_holo_dark</item>
</style>
<style name="Widget.Quantum.CompoundButton" parent="Widget.CompoundButton"/>
@@ -459,10 +459,10 @@
<style name="Widget.Quantum.EditText" parent="Widget.EditText"/>
<style name="Widget.Quantum.ExpandableListView" parent="Widget.Quantum.ListView">
- <item name="android:groupIndicator">@android:drawable/expander_group_holo_dark</item>
- <item name="android:indicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="android:indicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
- <item name="android:childDivider">?android:attr/listDivider</item>
+ <item name="groupIndicator">@drawable/expander_group_holo_dark</item>
+ <item name="indicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="indicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="childDivider">?attr/listDivider</item>
</style>
<style name="Widget.Quantum.ExpandableListView.White"/>
@@ -474,52 +474,52 @@
<style name="Widget.Quantum.GestureOverlayView" parent="Widget.GestureOverlayView"/>
<style name="Widget.Quantum.GridView" parent="Widget.GridView">
- <item name="android:listSelector">?android:attr/selectableItemBackground</item>
+ <item name="listSelector">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.CalendarView" parent="Widget.CalendarView">
- <item name="android:selectedWeekBackgroundColor">#330099FF</item>
- <item name="android:focusedMonthDateColor">#FFFFFFFF</item>
- <item name="android:unfocusedMonthDateColor">#66FFFFFF</item>
- <item name="android:weekNumberColor">#33FFFFFF</item>
- <item name="android:weekSeparatorLineColor">#19FFFFFF</item>
- <item name="android:selectedDateVerticalBar">@android:drawable/day_picker_week_view_dayline_holo</item>
- <item name="android:weekDayTextAppearance">@android:style/TextAppearance.Quantum.CalendarViewWeekDayView</item>
+ <item name="selectedWeekBackgroundColor">#330099FF</item>
+ <item name="focusedMonthDateColor">#FFFFFFFF</item>
+ <item name="unfocusedMonthDateColor">#66FFFFFF</item>
+ <item name="weekNumberColor">#33FFFFFF</item>
+ <item name="weekSeparatorLineColor">#19FFFFFF</item>
+ <item name="selectedDateVerticalBar">@drawable/day_picker_week_view_dayline_holo</item>
+ <item name="weekDayTextAppearance">@style/TextAppearance.Quantum.CalendarViewWeekDayView</item>
</style>
<style name="Widget.Quantum.ImageButton" parent="Widget.ImageButton">
- <item name="android:background">@android:drawable/btn_default_holo_dark</item>
+ <item name="background">@drawable/btn_default_quantum_dark</item>
</style>
<style name="Widget.Quantum.NumberPicker" parent="Widget.NumberPicker">
- <item name="android:internalLayout">@android:layout/number_picker_with_selector_wheel</item>
- <item name="android:solidColor">@android:color/transparent</item>
- <item name="android:selectionDivider">@android:drawable/numberpicker_selection_divider</item>
- <item name="android:selectionDividerHeight">2dip</item>
- <item name="android:selectionDividersDistance">48dip</item>
- <item name="android:internalMinWidth">64dip</item>
- <item name="android:internalMaxHeight">180dip</item>
- <item name="virtualButtonPressedDrawable">?android:attr/selectableItemBackground</item>
+ <item name="internalLayout">@layout/number_picker_with_selector_wheel</item>
+ <item name="solidColor">@color/transparent</item>
+ <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
+ <item name="selectionDividerHeight">2dip</item>
+ <item name="selectionDividersDistance">48dip</item>
+ <item name="internalMinWidth">64dip</item>
+ <item name="internalMaxHeight">180dip</item>
+ <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
</style>
<style name="Widget.Quantum.TimePicker" parent="Widget.TimePicker">
- <item name="android:legacyLayout">@android:layout/time_picker_legacy_holo</item>
- <item name="android:internalLayout">@android:layout/time_picker_holo</item>
- <item name="android:disabledColor">@android:color/timepicker_default_disabled_color_holo_dark</item>
- <item name="android:headerSelectedTextColor">@android:color/holo_blue_light</item>
- <item name="android:headerUnselectedTextColor">@android:color/timepicker_default_text_color_holo_dark</item>
- <item name="android:headerBackgroundColor">@android:color/timepicker_default_background_holo_dark</item>
- <item name="android:numbersTextColor">@android:color/timepicker_default_text_color_holo_dark</item>
- <item name="android:numbersBackgroundColor">@android:color/timepicker_default_background_holo_dark</item>
- <item name="android:amPmTextColor">@android:color/timepicker_default_text_color_holo_dark</item>
- <item name="android:amPmUnselectedBackgroundColor">@android:color/timepicker_default_background_holo_dark</item>
- <item name="android:amPmSelectedBackgroundColor">@android:color/holo_blue_light</item>
- <item name="android:numbersSelectorColor">@android:color/holo_blue_light</item>
+ <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+ <item name="internalLayout">@layout/time_picker_holo</item>
+ <item name="disabledColor">@color/timepicker_default_disabled_color_quantum_dark</item>
+ <item name="headerSelectedTextColor">@color/holo_blue_light</item>
+ <item name="headerUnselectedTextColor">@color/timepicker_default_text_color_quantum_dark</item>
+ <item name="headerBackgroundColor">@color/timepicker_default_background_quantum_dark</item>
+ <item name="numbersTextColor">@color/timepicker_default_text_color_quantum_dark</item>
+ <item name="numbersBackgroundColor">@color/timepicker_default_background_quantum_dark</item>
+ <item name="amPmTextColor">@color/timepicker_default_text_color_quantum_dark</item>
+ <item name="amPmUnselectedBackgroundColor">@color/timepicker_default_background_quantum_dark</item>
+ <item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
+ <item name="numbersSelectorColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Quantum.DatePicker" parent="Widget.DatePicker">
- <item name="android:internalLayout">@android:layout/date_picker_holo</item>
- <item name="android:calendarViewShown">true</item>
+ <item name="internalLayout">@layout/date_picker_holo</item>
+ <item name="calendarViewShown">true</item>
</style>
<style name="Widget.Quantum.ActivityChooserView" parent="Widget.ActivityChooserView"/>
@@ -527,8 +527,8 @@
<style name="Widget.Quantum.ImageWell" parent="Widget.ImageWell"/>
<style name="Widget.Quantum.ListView" parent="Widget.ListView">
- <item name="android:divider">?android:attr/listDivider</item>
- <item name="android:listSelector">?android:attr/listChoiceBackgroundIndicator</item>
+ <item name="divider">?attr/listDivider</item>
+ <item name="listSelector">?attr/listChoiceBackgroundIndicator</item>
</style>
<style name="Widget.Quantum.ListView.White"/>
@@ -536,29 +536,29 @@
<style name="Widget.Quantum.PopupWindow" parent="Widget.PopupWindow"/>
<style name="Widget.Quantum.PopupWindow.ActionMode">
- <item name="android:popupBackground">@android:color/black</item>
- <item name="android:popupAnimationStyle">@android:style/Animation.PopupWindow.ActionMode</item>
+ <item name="popupBackground">@color/black</item>
+ <item name="popupAnimationStyle">@style/Animation.PopupWindow.ActionMode</item>
</style>
<style name="Widget.Quantum.ProgressBar" parent="Widget.ProgressBar">
- <item name="android:indeterminateDrawable">@android:drawable/progress_medium_holo</item>
+ <item name="indeterminateDrawable">@drawable/progress_medium_holo</item>
</style>
<style name="Widget.Quantum.ProgressBar.Horizontal" parent="Widget.ProgressBar.Horizontal">
- <item name="android:progressDrawable">@android:drawable/progress_horizontal_holo_dark</item>
- <item name="android:indeterminateDrawable">@android:drawable/progress_indeterminate_horizontal_holo</item>
- <item name="android:minHeight">16dip</item>
- <item name="android:maxHeight">16dip</item>
+ <item name="progressDrawable">@drawable/progress_horizontal_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/progress_indeterminate_horizontal_holo</item>
+ <item name="minHeight">16dip</item>
+ <item name="maxHeight">16dip</item>
</style>
<style name="Widget.Quantum.ProgressBar.Small" parent="Widget.ProgressBar.Small">
- <item name="android:indeterminateDrawable">@android:drawable/progress_small_holo</item>
+ <item name="indeterminateDrawable">@drawable/progress_small_holo</item>
</style>
<style name="Widget.Quantum.ProgressBar.Small.Title"/>
<style name="Widget.Quantum.ProgressBar.Large" parent="Widget.ProgressBar.Large">
- <item name="android:indeterminateDrawable">@android:drawable/progress_large_holo</item>
+ <item name="indeterminateDrawable">@drawable/progress_large_holo</item>
</style>
<style name="Widget.Quantum.ProgressBar.Inverse"/>
@@ -568,36 +568,36 @@
<style name="Widget.Quantum.ProgressBar.Large.Inverse"/>
<style name="Widget.Quantum.SeekBar">
- <item name="android:indeterminateOnly">false</item>
- <item name="android:progressDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item>
- <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item>
- <item name="android:minHeight">13dip</item>
- <item name="android:maxHeight">13dip</item>
- <item name="android:thumb">@android:drawable/scrubber_control_selector_holo</item>
- <item name="android:thumbOffset">16dip</item>
- <item name="android:focusable">true</item>
- <item name="android:paddingStart">16dip</item>
- <item name="android:paddingEnd">16dip</item>
- <item name="android:mirrorForRtl">true</item>
+ <item name="indeterminateOnly">false</item>
+ <item name="progressDrawable">@drawable/scrubber_progress_horizontal_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_holo_dark</item>
+ <item name="minHeight">13dip</item>
+ <item name="maxHeight">13dip</item>
+ <item name="thumb">@drawable/scrubber_control_selector_holo</item>
+ <item name="thumbOffset">16dip</item>
+ <item name="focusable">true</item>
+ <item name="paddingStart">16dip</item>
+ <item name="paddingEnd">16dip</item>
+ <item name="mirrorForRtl">true</item>
</style>
<style name="Widget.Quantum.RatingBar" parent="Widget.RatingBar">
- <item name="android:progressDrawable">@android:drawable/ratingbar_full_holo_dark</item>
- <item name="android:indeterminateDrawable">@android:drawable/ratingbar_full_holo_dark</item>
+ <item name="progressDrawable">@drawable/ratingbar_full_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_dark</item>
</style>
<style name="Widget.Quantum.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
- <item name="android:progressDrawable">@android:drawable/ratingbar_holo_dark</item>
- <item name="android:indeterminateDrawable">@android:drawable/ratingbar_holo_dark</item>
- <item name="android:minHeight">35dip</item>
- <item name="android:maxHeight">35dip</item>
+ <item name="progressDrawable">@drawable/ratingbar_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_holo_dark</item>
+ <item name="minHeight">35dip</item>
+ <item name="maxHeight">35dip</item>
</style>
<style name="Widget.Quantum.RatingBar.Small" parent="Widget.RatingBar.Small">
- <item name="android:progressDrawable">@android:drawable/ratingbar_small_holo_dark</item>
- <item name="android:indeterminateDrawable">@android:drawable/ratingbar_small_holo_dark</item>
- <item name="android:minHeight">16dip</item>
- <item name="android:maxHeight">16dip</item>
+ <item name="progressDrawable">@drawable/ratingbar_small_holo_dark</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_dark</item>
+ <item name="minHeight">16dip</item>
+ <item name="maxHeight">16dip</item>
</style>
<style name="Widget.Quantum.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton"/>
@@ -607,47 +607,47 @@
<style name="Widget.Quantum.HorizontalScrollView" parent="Widget.HorizontalScrollView"/>
<style name="Widget.Quantum.Spinner" parent="Widget.Spinner.DropDown">
- <item name="android:background">@android:drawable/spinner_background_holo_dark</item>
- <item name="android:dropDownSelector">@android:drawable/list_selector_holo_dark</item>
- <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
- <item name="android:dropDownVerticalOffset">0dip</item>
- <item name="android:dropDownHorizontalOffset">0dip</item>
- <item name="android:dropDownWidth">wrap_content</item>
- <item name="android:popupPromptView">@android:layout/simple_dropdown_hint</item>
- <item name="android:gravity">start|center_vertical</item>
- <item name="android:disableChildrenWhenDisabled">true</item>
+ <item name="background">@drawable/spinner_background_holo_dark</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum_dark</item>
+ <item name="popupBackground">@drawable/menu_dropdown_panel_holo_dark</item>
+ <item name="dropDownVerticalOffset">0dip</item>
+ <item name="dropDownHorizontalOffset">0dip</item>
+ <item name="dropDownWidth">wrap_content</item>
+ <item name="popupPromptView">@layout/simple_dropdown_hint</item>
+ <item name="gravity">start|center_vertical</item>
+ <item name="disableChildrenWhenDisabled">true</item>
</style>
<style name="Widget.Quantum.Spinner.DropDown"/>
<style name="Widget.Quantum.Spinner.DropDown.ActionBar">
- <item name="android:background">@android:drawable/spinner_ab_holo_dark</item>
+ <item name="background">@drawable/spinner_ab_holo_dark</item>
</style>
<style name="Widget.Quantum.CompoundButton.Star" parent="Widget.CompoundButton.Star">
- <item name="android:button">@android:drawable/btn_star_holo_dark</item>
+ <item name="button">@drawable/btn_star_holo_dark</item>
</style>
<style name="Widget.Quantum.TabWidget" parent="Widget.TabWidget">
- <item name="android:tabStripLeft">@null</item>
- <item name="android:tabStripRight">@null</item>
- <item name="android:tabStripEnabled">false</item>
- <item name="android:divider">?android:attr/dividerVertical</item>
- <item name="android:showDividers">middle</item>
- <item name="android:dividerPadding">8dip</item>
- <item name="android:measureWithLargestChild">true</item>
- <item name="android:tabLayout">@android:layout/tab_indicator_holo</item>
+ <item name="tabStripLeft">@null</item>
+ <item name="tabStripRight">@null</item>
+ <item name="tabStripEnabled">false</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="showDividers">middle</item>
+ <item name="dividerPadding">8dip</item>
+ <item name="measureWithLargestChild">true</item>
+ <item name="tabLayout">@layout/tab_indicator_holo</item>
</style>
<style name="Widget.Quantum.Tab" parent="Widget.Quantum.ActionBar.TabView">
- <item name="android:background">@android:drawable/tab_indicator_holo</item>
- <item name="android:layout_width">0dip</item>
- <item name="android:layout_weight">1</item>
- <item name="android:minWidth">80dip</item>
+ <item name="background">@drawable/tab_indicator_holo</item>
+ <item name="layout_width">0dip</item>
+ <item name="layout_weight">1</item>
+ <item name="minWidth">80dip</item>
</style>
<style name="Widget.Quantum.TabText" parent="Widget.Quantum.ActionBar.TabText">
- <item name="android:maxWidth">180dip</item>
+ <item name="maxWidth">180dip</item>
</style>
<style name="Widget.Quantum.WebTextView" parent="Widget.WebTextView"/>
@@ -655,17 +655,17 @@
<style name="Widget.Quantum.WebView" parent="Widget.WebView"/>
<style name="Widget.Quantum.DropDownItem" parent="Widget.DropDownItem">
- <item name="android:textAppearance">@style/TextAppearance.Quantum.Widget.DropDownItem</item>
- <item name="android:paddingStart">8dp</item>
- <item name="android:paddingEnd">8dp</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.Widget.DropDownItem</item>
+ <item name="paddingStart">8dp</item>
+ <item name="paddingEnd">8dp</item>
</style>
<style name="Widget.Quantum.DropDownItem.Spinner"/>
<style name="Widget.Quantum.TextView.SpinnerItem" parent="Widget.TextView.SpinnerItem">
- <item name="android:textAppearance">@style/TextAppearance.Quantum.Widget.TextView.SpinnerItem</item>
- <item name="android:paddingStart">8dp</item>
- <item name="android:paddingEnd">8dp</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.Widget.TextView.SpinnerItem</item>
+ <item name="paddingStart">8dp</item>
+ <item name="paddingEnd">8dp</item>
</style>
<style name="Widget.Quantum.KeyboardView" parent="Widget.KeyboardView"/>
@@ -683,104 +683,104 @@
<style name="Widget.Quantum.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
<style name="Widget.Quantum.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="android:dropDownSelector">@android:drawable/list_selector_holo_dark</item>
- <item name="android:popupBackground">@android:drawable/menu_panel_holo_dark</item>
- <item name="android:dropDownVerticalOffset">0dip</item>
- <item name="android:dropDownHorizontalOffset">0dip</item>
- <item name="android:dropDownWidth">wrap_content</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum_dark</item>
+ <item name="popupBackground">@drawable/menu_panel_holo_dark</item>
+ <item name="dropDownVerticalOffset">0dip</item>
+ <item name="dropDownHorizontalOffset">0dip</item>
+ <item name="dropDownWidth">wrap_content</item>
</style>
<style name="Widget.Quantum.PopupMenu" parent="Widget.Quantum.ListPopupWindow"/>
<style name="Widget.Quantum.ButtonBar">
- <item name="android:divider">?android:attr/dividerVertical</item>
+ <item name="divider">?attr/dividerVertical</item>
</style>
<style name="Widget.Quantum.ButtonBar.Button"/>
<style name="Widget.Quantum.ActionButton" parent="Widget.ActionButton">
- <item name="android:minWidth">@android:dimen/action_button_min_width</item>
- <item name="android:gravity">center</item>
- <item name="android:paddingStart">12dip</item>
- <item name="android:paddingEnd">12dip</item>
- <item name="android:scaleType">center</item>
- <item name="android:maxLines">2</item>
+ <item name="minWidth">@dimen/action_button_min_width</item>
+ <item name="gravity">center</item>
+ <item name="paddingStart">12dip</item>
+ <item name="paddingEnd">12dip</item>
+ <item name="scaleType">center</item>
+ <item name="maxLines">2</item>
</style>
<style name="Widget.Quantum.ActionButton.Overflow">
- <item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_dark</item>
- <item name="android:background">?android:attr/actionBarItemBackground</item>
- <item name="android:contentDescription">@string/action_menu_overflow_description</item>
+ <item name="src">@drawable/ic_menu_moreoverflow_holo_dark</item>
+ <item name="background">?attr/actionBarItemBackground</item>
+ <item name="contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Quantum.ActionButton.TextButton" parent="Widget.Quantum.ButtonBar.Button"/>
<style name="Widget.Quantum.ActionBar.TabView" parent="Widget.ActionBar.TabView">
- <item name="android:background">@drawable/tab_indicator_ab_holo</item>
- <item name="android:paddingStart">16dip</item>
- <item name="android:paddingEnd">16dip</item>
+ <item name="background">@drawable/tab_indicator_ab_holo</item>
+ <item name="paddingStart">16dip</item>
+ <item name="paddingEnd">16dip</item>
</style>
<style name="Widget.Quantum.ActionBar.TabBar" parent="Widget.ActionBar.TabBar">
- <item name="android:divider">?android:attr/actionBarDivider</item>
- <item name="android:showDividers">middle</item>
- <item name="android:dividerPadding">12dip</item>
+ <item name="divider">?attr/actionBarDivider</item>
+ <item name="showDividers">middle</item>
+ <item name="dividerPadding">12dip</item>
</style>
<style name="Widget.Quantum.ActionBar.TabText" parent="Widget.ActionBar.TabText">
- <item name="android:textAppearance">@style/TextAppearance.Quantum.Medium</item>
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textSize">12sp</item>
- <item name="android:textStyle">bold</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:ellipsize">marquee</item>
- <item name="android:maxLines">2</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.Medium</item>
+ <item name="textColor">?attr/textColorPrimary</item>
+ <item name="textSize">12sp</item>
+ <item name="textStyle">bold</item>
+ <item name="textAllCaps">true</item>
+ <item name="ellipsize">marquee</item>
+ <item name="maxLines">2</item>
</style>
<style name="Widget.Quantum.ActionMode" parent="Widget.ActionMode">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionMode.Title</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionMode.Subtitle</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Subtitle</item>
</style>
<style name="Widget.Quantum.ActionButton.CloseMode">
- <item name="android:background">@drawable/btn_cab_done_holo_dark</item>
+ <item name="background">@drawable/btn_cab_done_holo_dark</item>
</style>
<style name="Widget.Quantum.ActionBar" parent="Widget.ActionBar">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="android:background">@android:drawable/ab_transparent_dark_holo</item>
- <item name="android:backgroundStacked">@android:drawable/ab_stacked_transparent_dark_holo</item>
- <item name="android:backgroundSplit">@android:drawable/ab_bottom_transparent_dark_holo</item>
- <item name="android:divider">?android:attr/dividerVertical</item>
- <item name="android:progressBarStyle">@android:style/Widget.Quantum.ProgressBar.Horizontal</item>
- <item name="android:indeterminateProgressStyle">@android:style/Widget.Quantum.ProgressBar</item>
- <item name="android:progressBarPadding">32dip</item>
- <item name="android:itemPadding">8dip</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
+ <item name="background">@drawable/ab_transparent_dark_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_transparent_dark_holo</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_transparent_dark_holo</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
+ <item name="progressBarPadding">32dip</item>
+ <item name="itemPadding">8dip</item>
</style>
<style name="Widget.Quantum.ActionBar.Solid">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="android:background">@android:drawable/ab_solid_dark_holo</item>
- <item name="android:backgroundStacked">@android:drawable/ab_stacked_solid_dark_holo</item>
- <item name="android:backgroundSplit">@android:drawable/ab_bottom_solid_dark_holo</item>
- <item name="android:divider">?android:attr/dividerVertical</item>
- <item name="android:progressBarStyle">@android:style/Widget.Quantum.ProgressBar.Horizontal</item>
- <item name="android:indeterminateProgressStyle">@android:style/Widget.Quantum.ProgressBar</item>
- <item name="android:progressBarPadding">32dip</item>
- <item name="android:itemPadding">8dip</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
+ <item name="background">@drawable/ab_solid_dark_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_solid_dark_holo</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_solid_dark_holo</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
+ <item name="progressBarPadding">32dip</item>
+ <item name="itemPadding">8dip</item>
</style>
<style name="Widget.Quantum.CompoundButton.Switch">
- <item name="android:track">@android:drawable/switch_track_holo_dark</item>
- <item name="android:thumb">@android:drawable/switch_inner_holo_dark</item>
- <item name="android:switchTextAppearance">@android:style/TextAppearance.Quantum.Widget.Switch</item>
- <item name="android:textOn">@android:string/capital_on</item>
- <item name="android:textOff">@android:string/capital_off</item>
- <item name="android:thumbTextPadding">12dip</item>
- <item name="android:switchMinWidth">96dip</item>
- <item name="android:switchPadding">16dip</item>
+ <item name="track">@drawable/switch_track_holo_dark</item>
+ <item name="thumb">@drawable/switch_inner_holo_dark</item>
+ <item name="switchTextAppearance">@style/TextAppearance.Quantum.Widget.Switch</item>
+ <item name="textOn">@string/capital_on</item>
+ <item name="textOff">@string/capital_off</item>
+ <item name="thumbTextPadding">12dip</item>
+ <item name="switchMinWidth">96dip</item>
+ <item name="switchPadding">16dip</item>
</style>
<!-- Light widget styles -->
@@ -788,51 +788,51 @@
<style name="Widget.Quantum.Light"/>
<style name="Widget.Quantum.Light.Button" parent="Widget.Button">
- <item name="android:background">@android:drawable/btn_default_holo_light</item>
- <item name="android:textAppearance">?android:attr/textAppearanceMediumInverse</item>
- <item name="android:textColor">@android:color/primary_text_holo_light</item>
- <item name="android:minHeight">48dip</item>
- <item name="android:minWidth">64dip</item>
+ <item name="background">@drawable/btn_default_quantum_light</item>
+ <item name="textAppearance">?attr/textAppearanceMediumInverse</item>
+ <item name="textColor">@color/primary_text_quantum_light</item>
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">64dip</item>
</style>
<style name="Widget.Quantum.Light.Button.Borderless">
- <item name="android:background">?android:attr/selectableItemBackground</item>
- <item name="android:paddingStart">4dip</item>
- <item name="android:paddingEnd">4dip</item>
+ <item name="background">?attr/selectableItemBackground</item>
+ <item name="paddingStart">4dip</item>
+ <item name="paddingEnd">4dip</item>
</style>
<style name="Widget.Quantum.Light.Button.Borderless.Small">
- <item name="android:textSize">14sp</item>
+ <item name="textSize">14sp</item>
</style>
<style name="Widget.Quantum.Light.Button.Small">
- <item name="android:background">@android:drawable/btn_default_holo_light</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:textColor">@android:color/primary_text_holo_light</item>
- <item name="android:minHeight">48dip</item>
- <item name="android:minWidth">48dip</item>
+ <item name="background">@drawable/btn_default_quantum_light</item>
+ <item name="textAppearance">?attr/textAppearanceSmall</item>
+ <item name="textColor">@color/primary_text_quantum_light</item>
+ <item name="minHeight">48dip</item>
+ <item name="minWidth">48dip</item>
</style>
<style name="Widget.Quantum.Light.Button.Inset"/>
<style name="Widget.Quantum.Light.Button.Toggle">
- <item name="android:background">@android:drawable/btn_toggle_holo_light</item>
- <item name="android:textOn">@android:string/capital_on</item>
- <item name="android:textOff">@android:string/capital_off</item>
- <item name="android:disabledAlpha">?android:attr/disabledAlpha</item>
- <item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
- <item name="android:minHeight">48dip</item>
+ <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="disabledAlpha">?attr/disabledAlpha</item>
+ <item name="textAppearance">?attr/textAppearanceSmall</item>
+ <item name="minHeight">48dip</item>
</style>
<style name="Quantum.Light.ButtonBar" parent="Quantum.ButtonBar"/>
<style name="Quantum.Light.ButtonBar.AlertDialog">
- <item name="android:background">@null</item>
- <item name="android:dividerPadding">0dp</item>
+ <item name="background">@null</item>
+ <item name="dividerPadding">0dp</item>
</style>
<style name="Quantum.Light.SegmentedButton" parent="SegmentedButton">
- <item name="android:background">@android:drawable/btn_group_holo_light</item>
+ <item name="background">@drawable/btn_group_holo_light</item>
</style>
<style name="Widget.Quantum.Light.TextView" parent="Widget.TextView"/>
@@ -840,8 +840,8 @@
<style name="Widget.Quantum.Light.CheckedTextView" parent="Widget.CheckedTextView"/>
<style name="Widget.Quantum.Light.TextView.ListSeparator" parent="Widget.TextView.ListSeparator">
- <item name="android:background">@android:drawable/list_section_divider_holo_light</item>
- <item name="android:textAllCaps">true</item>
+ <item name="background">@drawable/list_section_divider_holo_light</item>
+ <item name="textAllCaps">true</item>
</style>
<style name="Widget.Quantum.Light.TextSelectHandle" parent="Widget.TextSelectHandle"/>
@@ -851,8 +851,8 @@
<style name="Widget.Quantum.Light.AbsListView" parent="Widget.AbsListView"/>
<style name="Widget.Quantum.Light.AutoCompleteTextView" parent="Widget.AutoCompleteTextView">
- <item name="android:dropDownSelector">@android:drawable/list_selector_holo_light</item>
- <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum_light</item>
+ <item name="popupBackground">@drawable/menu_dropdown_panel_holo_light</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox"/>
@@ -862,10 +862,10 @@
<style name="Widget.Quantum.Light.EditText" parent="Widget.Quantum.EditText"/>
<style name="Widget.Quantum.Light.ExpandableListView" parent="Widget.Quantum.Light.ListView">
- <item name="android:groupIndicator">@android:drawable/expander_group_holo_light</item>
- <item name="android:indicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="android:indicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
- <item name="android:childDivider">?android:attr/listDivider</item>
+ <item name="groupIndicator">@drawable/expander_group_holo_light</item>
+ <item name="indicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="indicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="childDivider">?attr/listDivider</item>
</style>
<style name="Widget.Quantum.Light.ExpandableListView.White"/>
@@ -879,39 +879,39 @@
<style name="Widget.Quantum.Light.GridView" parent="Widget.Quantum.GridView"/>
<style name="Widget.Quantum.Light.ImageButton" parent="Widget.Quantum.ImageButton">
- <item name="android:background">@android:drawable/btn_default_holo_light</item>
+ <item name="background">@drawable/btn_default_quantum_light</item>
</style>
<style name="Widget.Quantum.Light.CalendarView" parent="Widget.CalendarView">
- <item name="android:selectedWeekBackgroundColor">#330066ff</item>
- <item name="android:focusedMonthDateColor">#FF000000</item>
- <item name="android:unfocusedMonthDateColor">#7F08002B</item>
- <item name="android:weekNumberColor">#7F080021</item>
- <item name="android:weekSeparatorLineColor">#7F08002A</item>
- <item name="android:weekDayTextAppearance">@android:style/TextAppearance.Quantum.Light.CalendarViewWeekDayView</item>
+ <item name="selectedWeekBackgroundColor">#330066ff</item>
+ <item name="focusedMonthDateColor">#FF000000</item>
+ <item name="unfocusedMonthDateColor">#7F08002B</item>
+ <item name="weekNumberColor">#7F080021</item>
+ <item name="weekSeparatorLineColor">#7F08002A</item>
+ <item name="weekDayTextAppearance">@style/TextAppearance.Quantum.Light.CalendarViewWeekDayView</item>
</style>
<style name="Widget.Quantum.Light.NumberPicker" parent="Widget.Quantum.NumberPicker"/>
<style name="Widget.Quantum.Light.TimePicker" parent="Widget.TimePicker">
- <item name="android:legacyLayout">@android:layout/time_picker_legacy_holo</item>
- <item name="android:internalLayout">@android:layout/time_picker_holo</item>
- <item name="android:disabledColor">@android:color/timepicker_default_disabled_color_holo_light</item>
- <item name="android:headerSelectedTextColor">@android:color/holo_blue_light</item>
- <item name="android:headerUnselectedTextColor">@android:color/timepicker_default_text_color_holo_light</item>
- <item name="android:headerBackgroundColor">@android:color/timepicker_default_background_holo_light</item>
- <item name="android:numbersTextColor">@android:color/timepicker_default_text_color_holo_light</item>
- <item name="android:numbersBackgroundColor">@android:color/timepicker_default_background_holo_light</item>
- <item name="android:amPmTextColor">@android:color/timepicker_default_text_color_holo_light</item>
- <item name="android:amPmUnselectedBackgroundColor">@android:color/timepicker_default_background_holo_light</item>
- <item name="android:amPmSelectedBackgroundColor">@android:color/holo_blue_light</item>
- <item name="android:numbersSelectorColor">@android:color/holo_blue_light</item>
+ <item name="legacyLayout">@layout/time_picker_legacy_holo</item>
+ <item name="internalLayout">@layout/time_picker_holo</item>
+ <item name="disabledColor">@color/timepicker_default_disabled_color_quantum_light</item>
+ <item name="headerSelectedTextColor">@color/holo_blue_light</item>
+ <item name="headerUnselectedTextColor">@color/timepicker_default_text_color_quantum_light</item>
+ <item name="headerBackgroundColor">@color/timepicker_default_background_quantum_light</item>
+ <item name="numbersTextColor">@color/timepicker_default_text_color_quantum_light</item>
+ <item name="numbersBackgroundColor">@color/timepicker_default_background_quantum_light</item>
+ <item name="amPmTextColor">@color/timepicker_default_text_color_quantum_light</item>
+ <item name="amPmUnselectedBackgroundColor">@color/timepicker_default_background_quantum_light</item>
+ <item name="amPmSelectedBackgroundColor">@color/holo_blue_light</item>
+ <item name="numbersSelectorColor">@color/holo_blue_light</item>
</style>
<style name="Widget.Quantum.Light.DatePicker" parent="Widget.Quantum.DatePicker"/>
<style name="Widget.Quantum.Light.ActivityChooserView" parent="Widget.Quantum.ActivityChooserView">
- <item name="android:background">@android:drawable/ab_share_pack_holo_light</item>
+ <item name="background">@drawable/ab_share_pack_holo_light</item>
</style>
<style name="Widget.Quantum.Light.ImageWell" parent="Widget.ImageWell"/>
@@ -923,14 +923,14 @@
<style name="Widget.Quantum.Light.PopupWindow" parent="Widget.PopupWindow"/>
<style name="Widget.Quantum.Light.PopupWindow.ActionMode">
- <item name="android:popupBackground">@android:color/white</item>
- <item name="android:popupAnimationStyle">@android:style/Animation.PopupWindow.ActionMode</item>
+ <item name="popupBackground">@color/white</item>
+ <item name="popupAnimationStyle">@style/Animation.PopupWindow.ActionMode</item>
</style>
<style name="Widget.Quantum.Light.ProgressBar" parent="Widget.Quantum.ProgressBar"/>
<style name="Widget.Quantum.Light.ProgressBar.Horizontal" parent="Widget.Quantum.ProgressBar.Horizontal">
- <item name="android:progressDrawable">@android:drawable/progress_horizontal_holo_light</item>
+ <item name="progressDrawable">@drawable/progress_horizontal_holo_light</item>
</style>
<style name="Widget.Quantum.Light.ProgressBar.Small" parent="Widget.Quantum.ProgressBar.Small"/>
@@ -946,27 +946,27 @@
<style name="Widget.Quantum.Light.ProgressBar.Large.Inverse" parent="Widget.Quantum.ProgressBar.Large.Inverse"/>
<style name="Widget.Quantum.Light.SeekBar" parent="Widget.Quantum.SeekBar">
- <item name="android:progressDrawable">@android:drawable/scrubber_progress_horizontal_holo_light</item>
- <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_light</item>
+ <item name="progressDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
+ <item name="indeterminateDrawable">@drawable/scrubber_progress_horizontal_holo_light</item>
</style>
<style name="Widget.Quantum.Light.RatingBar" parent="Widget.RatingBar">
- <item name="android:progressDrawable">@android:drawable/ratingbar_full_holo_light</item>
- <item name="android:indeterminateDrawable">@android:drawable/ratingbar_full_holo_light</item>
+ <item name="progressDrawable">@drawable/ratingbar_full_holo_light</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_full_holo_light</item>
</style>
<style name="Widget.Quantum.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
- <item name="android:progressDrawable">@android:drawable/ratingbar_holo_light</item>
- <item name="android:indeterminateDrawable">@android:drawable/ratingbar_holo_light</item>
- <item name="android:minHeight">35dip</item>
- <item name="android:maxHeight">35dip</item>
+ <item name="progressDrawable">@drawable/ratingbar_holo_light</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_holo_light</item>
+ <item name="minHeight">35dip</item>
+ <item name="maxHeight">35dip</item>
</style>
<style name="Widget.Quantum.Light.RatingBar.Small" parent="Widget.RatingBar.Small">
- <item name="android:progressDrawable">@android:drawable/ratingbar_small_holo_light</item>
- <item name="android:indeterminateDrawable">@android:drawable/ratingbar_small_holo_light</item>
- <item name="android:minHeight">16dip</item>
- <item name="android:maxHeight">16dip</item>
+ <item name="progressDrawable">@drawable/ratingbar_small_holo_light</item>
+ <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_light</item>
+ <item name="minHeight">16dip</item>
+ <item name="maxHeight">16dip</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton"/>
@@ -976,23 +976,23 @@
<style name="Widget.Quantum.Light.HorizontalScrollView" parent="Widget.HorizontalScrollView"/>
<style name="Widget.Quantum.Light.Spinner" parent="Widget.Quantum.Spinner">
- <item name="android:background">@android:drawable/spinner_background_holo_light</item>
- <item name="android:dropDownSelector">@android:drawable/list_selector_holo_light</item>
- <item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_light</item>
- <item name="android:dropDownVerticalOffset">0dip</item>
- <item name="android:dropDownHorizontalOffset">0dip</item>
- <item name="android:dropDownWidth">wrap_content</item>
- <item name="android:popupPromptView">@android:layout/simple_dropdown_hint</item>
+ <item name="background">@drawable/spinner_background_holo_light</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum_light</item>
+ <item name="popupBackground">@drawable/menu_dropdown_panel_holo_light</item>
+ <item name="dropDownVerticalOffset">0dip</item>
+ <item name="dropDownHorizontalOffset">0dip</item>
+ <item name="dropDownWidth">wrap_content</item>
+ <item name="popupPromptView">@layout/simple_dropdown_hint</item>
</style>
<style name="Widget.Quantum.Light.Spinner.DropDown"/>
<style name="Widget.Quantum.Light.Spinner.DropDown.ActionBar">
- <item name="android:background">@android:drawable/spinner_ab_holo_light</item>
+ <item name="background">@drawable/spinner_ab_holo_light</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton.Star" parent="Widget.CompoundButton.Star">
- <item name="android:button">@android:drawable/btn_star_holo_light</item>
+ <item name="button">@drawable/btn_star_holo_light</item>
</style>
<style name="Widget.Quantum.Light.TabWidget" parent="Widget.Quantum.TabWidget"/>
@@ -1022,11 +1022,11 @@
<style name="Widget.Quantum.Light.QuickContactBadgeSmall.WindowLarge" parent="Widget.QuickContactBadgeSmall.WindowLarge"/>
<style name="Widget.Quantum.Light.ListPopupWindow" parent="Widget.ListPopupWindow">
- <item name="android:dropDownSelector">@android:drawable/list_selector_holo_light</item>
- <item name="android:popupBackground">@android:drawable/menu_panel_holo_light</item>
- <item name="android:dropDownVerticalOffset">0dip</item>
- <item name="android:dropDownHorizontalOffset">0dip</item>
- <item name="android:dropDownWidth">wrap_content</item>
+ <item name="dropDownSelector">@drawable/list_selector_quantum_light</item>
+ <item name="popupBackground">@drawable/menu_panel_holo_light</item>
+ <item name="dropDownVerticalOffset">0dip</item>
+ <item name="dropDownHorizontalOffset">0dip</item>
+ <item name="dropDownWidth">wrap_content</item>
</style>
<style name="Widget.Quantum.Light.PopupMenu" parent="Widget.Quantum.Light.ListPopupWindow"/>
@@ -1034,17 +1034,17 @@
<style name="Widget.Quantum.Light.ActionButton" parent="Widget.Quantum.ActionButton"/>
<style name="Widget.Quantum.Light.ActionButton.Overflow">
- <item name="android:src">@android:drawable/ic_menu_moreoverflow_holo_light</item>
- <item name="android:contentDescription">@string/action_menu_overflow_description</item>
+ <item name="src">@drawable/ic_menu_moreoverflow_holo_light</item>
+ <item name="contentDescription">@string/action_menu_overflow_description</item>
</style>
<style name="Widget.Quantum.Light.ActionBar.TabView" parent="Widget.Quantum.ActionBar.TabView"/>
<style name="Widget.Quantum.Light.Tab" parent="Widget.Quantum.Light.ActionBar.TabView">
- <item name="android:background">@android:drawable/tab_indicator_holo</item>
- <item name="android:layout_width">0dip</item>
- <item name="android:layout_weight">1</item>
- <item name="android:minWidth">80dip</item>
+ <item name="background">@drawable/tab_indicator_holo</item>
+ <item name="layout_width">0dip</item>
+ <item name="layout_weight">1</item>
+ <item name="minWidth">80dip</item>
</style>
<style name="Widget.Quantum.Light.ActionBar.TabBar" parent="Widget.Quantum.ActionBar.TabBar"/>
@@ -1056,69 +1056,69 @@
<style name="Widget.Quantum.Light.ActionBar.TabBar.Inverse"/>
<style name="Widget.Quantum.Light.ActionBar.TabText.Inverse">
- <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="textColor">?attr/textColorPrimaryInverse</item>
</style>
<style name="Widget.Quantum.Light.ActionMode" parent="Widget.Quantum.ActionMode">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionMode.Title</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionMode.Subtitle</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Subtitle</item>
</style>
<style name="Widget.Quantum.Light.ActionMode.Inverse" parent="Widget.ActionMode">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionMode.Title.Inverse</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Title.Inverse</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionMode.Subtitle.Inverse</item>
</style>
<style name="Widget.Quantum.Light.ActionButton.CloseMode">
- <item name="android:background">@drawable/btn_cab_done_holo_light</item>
+ <item name="background">@drawable/btn_cab_done_holo_light</item>
</style>
<style name="Widget.Quantum.Light.ActionBar" parent="Widget.Quantum.ActionBar">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="android:background">@android:drawable/ab_transparent_light_holo</item>
- <item name="android:backgroundStacked">@android:drawable/ab_stacked_transparent_light_holo</item>
- <item name="android:backgroundSplit">@android:drawable/ab_bottom_transparent_light_holo</item>
- <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
- <item name="android:progressBarStyle">@android:style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
- <item name="android:indeterminateProgressStyle">@android:style/Widget.Quantum.Light.ProgressBar</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
+ <item name="background">@drawable/ab_transparent_light_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_transparent_light_holo</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_transparent_light_holo</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_holo_light</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
</style>
<style name="Widget.Quantum.Light.ActionBar.Solid">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
- <item name="android:background">@android:drawable/ab_solid_light_holo</item>
- <item name="android:backgroundStacked">@android:drawable/ab_stacked_solid_light_holo</item>
- <item name="android:backgroundSplit">@android:drawable/ab_bottom_solid_light_holo</item>
- <item name="android:divider">?android:attr/dividerVertical</item>
- <item name="android:progressBarStyle">@android:style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
- <item name="android:indeterminateProgressStyle">@android:style/Widget.Quantum.Light.ProgressBar</item>
- <item name="android:progressBarPadding">32dip</item>
- <item name="android:itemPadding">8dip</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
+ <item name="background">@drawable/ab_solid_light_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_solid_light_holo</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_solid_light_holo</item>
+ <item name="divider">?attr/dividerVertical</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Quantum.Light.ProgressBar</item>
+ <item name="progressBarPadding">32dip</item>
+ <item name="itemPadding">8dip</item>
</style>
<style name="Widget.Quantum.Light.ActionBar.Solid.Inverse">
- <item name="android:titleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Title.Inverse</item>
- <item name="android:subtitleTextStyle">@android:style/TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse</item>
- <item name="android:background">@android:drawable/ab_solid_dark_holo</item>
- <item name="android:backgroundStacked">@android:drawable/ab_stacked_solid_dark_holo</item>
- <item name="android:backgroundSplit">@android:drawable/ab_bottom_solid_inverse_holo</item>
- <item name="android:divider">@android:drawable/list_divider_holo_dark</item>
- <item name="android:progressBarStyle">@android:style/Widget.Quantum.ProgressBar.Horizontal</item>
- <item name="android:indeterminateProgressStyle">@android:style/Widget.Quantum.ProgressBar</item>
- <item name="android:progressBarPadding">32dip</item>
- <item name="android:itemPadding">8dip</item>
+ <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title.Inverse</item>
+ <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle.Inverse</item>
+ <item name="background">@drawable/ab_solid_dark_holo</item>
+ <item name="backgroundStacked">@drawable/ab_stacked_solid_dark_holo</item>
+ <item name="backgroundSplit">@drawable/ab_bottom_solid_inverse_holo</item>
+ <item name="divider">@drawable/list_divider_holo_dark</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar.Horizontal</item>
+ <item name="indeterminateProgressStyle">@style/Widget.Quantum.ProgressBar</item>
+ <item name="progressBarPadding">32dip</item>
+ <item name="itemPadding">8dip</item>
</style>
<style name="Widget.Quantum.Light.CompoundButton.Switch" parent="Widget.CompoundButton.Switch">
- <item name="android:track">@android:drawable/switch_track_holo_light</item>
- <item name="android:thumb">@android:drawable/switch_inner_holo_light</item>
- <item name="android:switchTextAppearance">@android:style/TextAppearance.Quantum.Light.Widget.Switch</item>
- <item name="android:textOn">@android:string/capital_on</item>
- <item name="android:textOff">@android:string/capital_off</item>
- <item name="android:thumbTextPadding">12dip</item>
- <item name="android:switchMinWidth">96dip</item>
- <item name="android:switchPadding">16dip</item>
+ <item name="track">@drawable/switch_track_holo_light</item>
+ <item name="thumb">@drawable/switch_inner_holo_light</item>
+ <item name="switchTextAppearance">@style/TextAppearance.Quantum.Light.Widget.Switch</item>
+ <item name="textOn">@string/capital_on</item>
+ <item name="textOff">@string/capital_off</item>
+ <item name="thumbTextPadding">12dip</item>
+ <item name="switchMinWidth">96dip</item>
+ <item name="switchPadding">16dip</item>
</style>
<!-- Animation Styles -->
@@ -1132,109 +1132,109 @@
<!-- Dialog styles -->
<style name="AlertDialog.Quantum" parent="AlertDialog">
- <item name="fullDark">@android:drawable/dialog_full_holo_dark</item>
- <item name="topDark">@android:drawable/dialog_top_holo_dark</item>
- <item name="centerDark">@android:drawable/dialog_middle_holo_dark</item>
- <item name="bottomDark">@android:drawable/dialog_bottom_holo_dark</item>
- <item name="fullBright">@android:drawable/dialog_full_holo_dark</item>
- <item name="topBright">@android:drawable/dialog_top_holo_dark</item>
- <item name="centerBright">@android:drawable/dialog_middle_holo_dark</item>
- <item name="bottomBright">@android:drawable/dialog_bottom_holo_dark</item>
- <item name="bottomMedium">@android:drawable/dialog_bottom_holo_dark</item>
- <item name="centerMedium">@android:drawable/dialog_middle_holo_dark</item>
- <item name="layout">@android:layout/alert_dialog_holo</item>
- <item name="listLayout">@android:layout/select_dialog_holo</item>
- <item name="progressLayout">@android:layout/progress_dialog_holo</item>
- <item name="horizontalProgressLayout">@android:layout/alert_dialog_progress_holo</item>
- <item name="listItemLayout">@android:layout/select_dialog_item_holo</item>
- <item name="multiChoiceItemLayout">@android:layout/select_dialog_multichoice_holo</item>
- <item name="singleChoiceItemLayout">@android:layout/select_dialog_singlechoice_holo</item>
+ <item name="fullDark">@drawable/dialog_full_holo_dark</item>
+ <item name="topDark">@drawable/dialog_top_holo_dark</item>
+ <item name="centerDark">@drawable/dialog_middle_holo_dark</item>
+ <item name="bottomDark">@drawable/dialog_bottom_holo_dark</item>
+ <item name="fullBright">@drawable/dialog_full_holo_dark</item>
+ <item name="topBright">@drawable/dialog_top_holo_dark</item>
+ <item name="centerBright">@drawable/dialog_middle_holo_dark</item>
+ <item name="bottomBright">@drawable/dialog_bottom_holo_dark</item>
+ <item name="bottomMedium">@drawable/dialog_bottom_holo_dark</item>
+ <item name="centerMedium">@drawable/dialog_middle_holo_dark</item>
+ <item name="layout">@layout/alert_dialog_holo</item>
+ <item name="listLayout">@layout/select_dialog_holo</item>
+ <item name="progressLayout">@layout/progress_dialog_holo</item>
+ <item name="horizontalProgressLayout">@layout/alert_dialog_progress_holo</item>
+ <item name="listItemLayout">@layout/select_dialog_item_holo</item>
+ <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_holo</item>
+ <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_holo</item>
</style>
<style name="AlertDialog.Quantum.Light">
- <item name="fullDark">@android:drawable/dialog_full_holo_light</item>
- <item name="topDark">@android:drawable/dialog_top_holo_light</item>
- <item name="centerDark">@android:drawable/dialog_middle_holo_light</item>
- <item name="bottomDark">@android:drawable/dialog_bottom_holo_light</item>
- <item name="fullBright">@android:drawable/dialog_full_holo_light</item>
- <item name="topBright">@android:drawable/dialog_top_holo_light</item>
- <item name="centerBright">@android:drawable/dialog_middle_holo_light</item>
- <item name="bottomBright">@android:drawable/dialog_bottom_holo_light</item>
- <item name="bottomMedium">@android:drawable/dialog_bottom_holo_light</item>
- <item name="centerMedium">@android:drawable/dialog_middle_holo_light</item>
+ <item name="fullDark">@drawable/dialog_full_holo_light</item>
+ <item name="topDark">@drawable/dialog_top_holo_light</item>
+ <item name="centerDark">@drawable/dialog_middle_holo_light</item>
+ <item name="bottomDark">@drawable/dialog_bottom_holo_light</item>
+ <item name="fullBright">@drawable/dialog_full_holo_light</item>
+ <item name="topBright">@drawable/dialog_top_holo_light</item>
+ <item name="centerBright">@drawable/dialog_middle_holo_light</item>
+ <item name="bottomBright">@drawable/dialog_bottom_holo_light</item>
+ <item name="bottomMedium">@drawable/dialog_bottom_holo_light</item>
+ <item name="centerMedium">@drawable/dialog_middle_holo_light</item>
</style>
<!-- Window title -->
<style name="WindowTitleBackground.Quantum">
- <item name="android:background">@null</item>
+ <item name="background">@null</item>
</style>
<style name="WindowTitle.Quantum">
- <item name="android:singleLine">true</item>
- <item name="android:textAppearance">@style/TextAppearance.Quantum.WindowTitle</item>
- <item name="android:shadowColor">#BB000000</item>
- <item name="android:shadowRadius">2.75</item>
+ <item name="singleLine">true</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.WindowTitle</item>
+ <item name="shadowColor">#BB000000</item>
+ <item name="shadowRadius">2.75</item>
</style>
<style name="DialogWindowTitle.Quantum">
- <item name="android:maxLines">1</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:textAppearance">@style/TextAppearance.Quantum.DialogWindowTitle</item>
+ <item name="maxLines">1</item>
+ <item name="scrollHorizontally">true</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.DialogWindowTitle</item>
</style>
<style name="DialogWindowTitle.Quantum.Light">
- <item name="android:maxLines">1</item>
- <item name="android:scrollHorizontally">true</item>
- <item name="android:textAppearance">@style/TextAppearance.Quantum.Light.DialogWindowTitle</item>
+ <item name="maxLines">1</item>
+ <item name="scrollHorizontally">true</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.Light.DialogWindowTitle</item>
</style>
<style name="Widget.Quantum.PreferenceFrameLayout">
- <item name="android:borderTop">0dip</item>
- <item name="android:borderBottom">@dimen/preference_fragment_padding_bottom</item>
- <item name="android:borderLeft">?attr/preferenceFragmentPaddingSide</item>
- <item name="android:borderRight">?attr/preferenceFragmentPaddingSide</item>
+ <item name="borderTop">0dip</item>
+ <item name="borderBottom">@dimen/preference_fragment_padding_bottom</item>
+ <item name="borderLeft">?attr/preferenceFragmentPaddingSide</item>
+ <item name="borderRight">?attr/preferenceFragmentPaddingSide</item>
</style>
<style name="Widget.Quantum.MediaRouteButton">
- <item name="android:background">?android:attr/selectableItemBackground</item>
- <item name="android:externalRouteEnabledDrawable">@drawable/ic_media_route_holo_dark</item>
- <item name="android:minWidth">56dp</item>
- <item name="android:minHeight">48dp</item>
- <item name="android:focusable">true</item>
- <item name="android:contentDescription">@android:string/media_route_button_content_description</item>
+ <item name="background">?attr/selectableItemBackground</item>
+ <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_dark</item>
+ <item name="minWidth">56dp</item>
+ <item name="minHeight">48dp</item>
+ <item name="focusable">true</item>
+ <item name="contentDescription">@string/media_route_button_content_description</item>
</style>
<style name="Widget.Quantum.Light.MediaRouteButton" parent="Widget.Quantum.MediaRouteButton">
- <item name="android:externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
+ <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_holo_light</item>
</style>
<style name="TextAppearance.Quantum.TimePicker.TimeLabel" parent="TextAppearance.Quantum">
- <item name="android:textSize">@dimen/timepicker_time_label_size</item>
- <item name="android:textColor">@android:color/timepicker_default_text_color_holo_dark</item>
+ <item name="textSize">@dimen/timepicker_time_label_size</item>
+ <item name="textColor">@color/timepicker_default_text_color_quantum_dark</item>
</style>
<style name="TextAppearance.Quantum.TimePicker.AmPmLabel" parent="TextAppearance.Quantum">
- <item name="android:textSize">@dimen/timepicker_ampm_label_size</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:textColor">@android:color/timepicker_default_text_color_holo_dark</item>
- <item name="android:textStyle">bold</item>
+ <item name="textSize">@dimen/timepicker_ampm_label_size</item>
+ <item name="textAllCaps">true</item>
+ <item name="textColor">@color/timepicker_default_text_color_quantum_dark</item>
+ <item name="textStyle">bold</item>
</style>
<style name="TextAppearance.Quantum.Light.TimePicker.TimeLabel" parent="TextAppearance.Quantum.Light">
- <item name="android:textSize">@dimen/timepicker_time_label_size</item>
- <item name="android:textColor">@color/timepicker_default_text_color_holo_light</item>
+ <item name="textSize">@dimen/timepicker_time_label_size</item>
+ <item name="textColor">@color/timepicker_default_text_color_quantum_light</item>
</style>
<style name="TextAppearance.Quantum.Light.TimePicker.AmPmLabel" parent="TextAppearance.Quantum.Light">
- <item name="android:textSize">@dimen/timepicker_ampm_label_size</item>
- <item name="android:textAllCaps">true</item>
- <item name="android:textColor">@color/timepicker_default_text_color_holo_light</item>
- <item name="android:textStyle">bold</item>
+ <item name="textSize">@dimen/timepicker_ampm_label_size</item>
+ <item name="textAllCaps">true</item>
+ <item name="textColor">@color/timepicker_default_text_color_quantum_light</item>
+ <item name="textStyle">bold</item>
</style>
<style name="Widget.Quantum.FastScroll" parent="Widget.FastScroll">
- <item name="android:thumbMinWidth">0dp</item>
- <item name="android:thumbMinHeight">0dp</item>
+ <item name="thumbMinWidth">0dp</item>
+ <item name="thumbMinHeight">0dp</item>
</style>
<style name="Widget.Quantum.Light.FastScroll" parent="Widget.Quantum.FastScroll"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3ac762f..9f368c4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -289,7 +289,7 @@
<java-symbol type="bool" name="config_useFixedVolume" />
<java-symbol type="bool" name="config_forceDefaultOrientation" />
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
- <java-symbol type="bool" name="flip_controller_fallback_keys" />
+ <java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
@@ -1501,6 +1501,7 @@
<java-symbol type="integer" name="config_screenBrightnessSettingMaximum" />
<java-symbol type="integer" name="config_screenBrightnessSettingDefault" />
<java-symbol type="integer" name="config_screenBrightnessDim" />
+ <java-symbol type="integer" name="config_screenBrightnessDoze" />
<java-symbol type="integer" name="config_shutdownBatteryTemperature" />
<java-symbol type="integer" name="config_undockedHdmiRotation" />
<java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
@@ -1605,11 +1606,18 @@
<java-symbol type="xml" name="storage_list" />
<java-symbol type="bool" name="config_dreamsSupported" />
<java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+ <java-symbol type="bool" name="config_dreamsEnabledOnBattery" />
<java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
<java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenPowered" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelMinimumWhenNotPowered" />
+ <java-symbol type="integer" name="config_dreamsBatteryLevelDrainCutoff" />
<java-symbol type="string" name="config_dreamsDefaultComponent" />
+ <java-symbol type="string" name="config_dozeComponent" />
<java-symbol type="string" name="enable_explore_by_touch_warning_title" />
<java-symbol type="string" name="enable_explore_by_touch_warning_message" />
+ <java-symbol type="bool" name="config_powerDecoupleAutoSuspendModeFromDisplay" />
+ <java-symbol type="bool" name="config_powerDecoupleInteractiveModeFromDisplay" />
<java-symbol type="layout" name="resolver_list" />
<java-symbol type="id" name="resolver_list" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7a654e6..4a0158e 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -365,7 +365,7 @@
<item name="searchViewCloseIcon">@android:drawable/ic_clear</item>
<item name="searchViewSearchIcon">@android:drawable/ic_search_api_holo_dark</item>
<item name="searchViewGoIcon">@android:drawable/ic_go</item>
- <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
+ <item name="searchViewVoiceIcon">@android:drawable/ic_voice_search_api_holo_dark</item>
<item name="searchViewEditQuery">@android:drawable/ic_commit_search_api_holo_dark</item>
<item name="searchViewEditQueryBackground">?attr/selectableItemBackground</item>
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index 0a197b9..f0db46c 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -33,7 +33,7 @@
<!-- Quantum Paper theme (dark version).
<p>If you want to ensure that your
app consistently uses the Quantum theme at all times, you must explicitly declare it in your
- manifest. For example, {@code <application android:theme="@android:style/Theme.Quantum">}.
+ manifest. For example, {@code <application android:theme="@style/Theme.Quantum">}.
<p>Styles used by the Quantum theme are named using the convention Type.Quantum.Etc
(for example, {@code Widget.Quantum.Button} and {@code
@@ -42,10 +42,10 @@
with trailing _dark or _light specifiers if they are not shared between both light and
dark versions of the theme. -->
<style name="Theme.Quantum">
- <item name="colorForeground">@android:color/bright_foreground_holo_dark</item>
- <item name="colorForegroundInverse">@android:color/bright_foreground_inverse_holo_dark</item>
- <item name="colorBackground">@android:color/background_holo_dark</item>
- <item name="colorBackgroundCacheHint">@android:drawable/background_cache_hint_selector_holo_dark</item>
+ <item name="colorForeground">@color/bright_foreground_quantum_dark</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_quantum_light</item>
+ <item name="colorBackground">@color/background_quantum_dark</item>
+ <item name="colorBackgroundCacheHint">@drawable/background_cache_hint_selector_quantum_dark</item>
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
@@ -56,72 +56,72 @@
<item name="colorActivatedHighlight">@color/holo_blue_dark</item>
<!-- Text styles -->
- <item name="textAppearance">@android:style/TextAppearance.Quantum</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.Quantum.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
- <item name="textColorPrimary">@android:color/primary_text_holo_dark</item>
- <item name="textColorSecondary">@android:color/secondary_text_holo_dark</item>
- <item name="textColorTertiary">@android:color/tertiary_text_holo_dark</item>
- <item name="textColorPrimaryInverse">@android:color/primary_text_holo_light</item>
- <item name="textColorSecondaryInverse">@android:color/secondary_text_holo_light</item>
- <item name="textColorTertiaryInverse">@android:color/tertiary_text_holo_light</item>
- <item name="textColorPrimaryDisableOnly">@android:color/primary_text_disable_only_holo_dark</item>
- <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_disable_only_holo_light</item>
- <item name="textColorPrimaryNoDisable">@android:color/primary_text_nodisable_holo_dark</item>
- <item name="textColorSecondaryNoDisable">@android:color/secondary_text_nodisable_holo_dark</item>
- <item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_nodisable_holo_light</item>
- <item name="textColorSecondaryInverseNoDisable">@android:color/secondary_text_nodisable_holo_light</item>
- <item name="textColorHint">@android:color/hint_foreground_holo_dark</item>
- <item name="textColorHintInverse">@android:color/hint_foreground_holo_light</item>
- <item name="textColorSearchUrl">@android:color/search_url_text_holo</item>
- <item name="textColorHighlight">@android:color/highlighted_text_holo_dark</item>
- <item name="textColorHighlightInverse">@android:color/highlighted_text_holo_light</item>
- <item name="textColorLink">@android:color/holo_blue_light</item>
- <item name="textColorLinkInverse">@android:color/holo_blue_light</item>
- <item name="textColorAlertDialogListItem">@android:color/primary_text_holo_dark</item>
+ <item name="textColorPrimary">@color/primary_text_quantum_dark</item>
+ <item name="textColorSecondary">@color/secondary_text_quantum_dark</item>
+ <item name="textColorTertiary">@color/tertiary_text_quantum_dark</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_quantum_light</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_quantum_light</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_light</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
+ <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_quantum_light</item>
+ <item name="textColorPrimaryNoDisable">@color/primary_text_nodisable_quantum_dark</item>
+ <item name="textColorSecondaryNoDisable">@color/secondary_text_nodisable_quantum_dark</item>
+ <item name="textColorPrimaryInverseNoDisable">@color/primary_text_nodisable_quantum_light</item>
+ <item name="textColorSecondaryInverseNoDisable">@color/secondary_text_nodisable_quantum_light</item>
+ <item name="textColorHint">@color/hint_foreground_quantum_dark</item>
+ <item name="textColorHintInverse">@color/hint_foreground_quantum_light</item>
+ <item name="textColorSearchUrl">@color/search_url_text_quantum_dark</item>
+ <item name="textColorHighlight">@color/highlighted_text_quantum_dark</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_quantum_light</item>
+ <item name="textColorLink">@color/holo_blue_light</item>
+ <item name="textColorLinkInverse">@color/holo_blue_light</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_quantum_dark</item>
- <item name="textAppearanceLarge">@android:style/TextAppearance.Quantum.Large</item>
- <item name="textAppearanceMedium">@android:style/TextAppearance.Quantum.Medium</item>
- <item name="textAppearanceSmall">@android:style/TextAppearance.Quantum.Small</item>
- <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Quantum.Large.Inverse</item>
- <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Quantum.Medium.Inverse</item>
- <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Quantum.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.Quantum.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.Quantum.SearchResult.Subtitle</item>
+ <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Large</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Medium</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Small</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Large.Inverse</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Medium.Inverse</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.SearchResult.Subtitle</item>
- <item name="textAppearanceButton">@android:style/TextAppearance.Quantum.Widget.Button</item>
+ <item name="textAppearanceButton">@style/TextAppearance.Quantum.Widget.Button</item>
- <item name="editTextColor">?android:attr/textColorPrimary</item>
- <item name="editTextBackground">@android:drawable/edit_text_holo_dark</item>
+ <item name="editTextColor">?attr/textColorPrimary</item>
+ <item name="editTextBackground">@drawable/edit_text_holo_dark</item>
- <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
+ <item name="candidatesTextStyleSpans">@string/candidates_style</item>
- <item name="textCheckMark">@android:drawable/indicator_check_mark_dark</item>
- <item name="textCheckMarkInverse">@android:drawable/indicator_check_mark_light</item>
+ <item name="textCheckMark">@drawable/indicator_check_mark_dark</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item>
- <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.Quantum.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.Quantum.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Widget.PopupMenu.Small</item>
<!-- Button styles -->
- <item name="buttonStyle">@android:style/Widget.Quantum.Button</item>
+ <item name="buttonStyle">@style/Widget.Quantum.Button</item>
- <item name="buttonStyleSmall">@android:style/Widget.Quantum.Button.Small</item>
- <item name="buttonStyleInset">@android:style/Widget.Quantum.Button.Inset</item>
+ <item name="buttonStyleSmall">@style/Widget.Quantum.Button.Small</item>
+ <item name="buttonStyleInset">@style/Widget.Quantum.Button.Inset</item>
- <item name="buttonStyleToggle">@android:style/Widget.Quantum.Button.Toggle</item>
- <item name="switchStyle">@android:style/Widget.Quantum.CompoundButton.Switch</item>
- <item name="mediaRouteButtonStyle">@android:style/Widget.Quantum.MediaRouteButton</item>
+ <item name="buttonStyleToggle">@style/Widget.Quantum.Button.Toggle</item>
+ <item name="switchStyle">@style/Widget.Quantum.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@style/Widget.Quantum.MediaRouteButton</item>
- <item name="selectableItemBackground">@android:drawable/item_background_holo_dark</item>
- <item name="borderlessButtonStyle">@android:style/Widget.Quantum.Button.Borderless</item>
- <item name="homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
+ <item name="selectableItemBackground">@drawable/item_background_quantum_dark</item>
+ <item name="borderlessButtonStyle">@style/Widget.Quantum.Button.Borderless</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_holo_dark</item>
<!-- List attributes -->
<item name="listPreferredItemHeight">64dip</item>
<item name="listPreferredItemHeightSmall">48dip</item>
<item name="listPreferredItemHeightLarge">80dip</item>
- <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
- <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item>
<item name="listPreferredItemPaddingLeft">8dip</item>
<item name="listPreferredItemPaddingRight">8dip</item>
<item name="listPreferredItemPaddingStart">8dip</item>
@@ -130,31 +130,32 @@
<!-- @hide -->
<item name="searchResultListItemHeight">58dip</item>
<item name="listDivider">@drawable/list_divider_holo_dark</item>
- <item name="listSeparatorTextViewStyle">@android:style/Widget.Quantum.TextView.ListSeparator</item>
+ <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.TextView.ListSeparator</item>
- <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_dark</item>
- <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_dark</item>
+ <item name="listChoiceIndicatorSingle">@drawable/btn_radio_holo_dark</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_holo_dark</item>
- <item name="listChoiceBackgroundIndicator">@android:drawable/list_selector_holo_dark</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum_dark</item>
- <item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_dark</item>
+ <item name="activatedBackgroundIndicator">@drawable/activated_background_holo_dark</item>
- <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_dark</item>
+ <item name="listDividerAlertDialog">@drawable/list_divider_holo_dark</item>
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
- <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
+ <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
<item name="expandableListPreferredItemIndicatorLeft">3dip</item>
<item name="expandableListPreferredItemIndicatorRight">0dip</item>
- <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
- <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_dark</item>
- <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_dark</item>
+ <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="findOnPageNextDrawable">@drawable/ic_find_next_holo_dark</item>
+ <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_holo_dark</item>
<!-- Gallery attributes -->
- <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
+ <item name="galleryItemBackground">@drawable/gallery_item_background</item>
<!-- Window attributes -->
+ <item name="windowBackground">@color/background_quantum_dark</item>
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
@@ -162,177 +163,177 @@
<item name="windowIsFloating">false</item>
<item name="windowContentOverlay">@null</item>
<item name="windowShowWallpaper">false</item>
- <item name="windowTitleStyle">@android:style/WindowTitle.Quantum</item>
+ <item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
<item name="windowTitleSize">25dip</item>
- <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.Quantum</item>
+ <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Quantum</item>
<item name="windowContentTransitions">true</item>
- <item name="windowAnimationStyle">@android:style/Animation.Quantum.Activity</item>
+ <item name="windowAnimationStyle">@style/Animation.Quantum.Activity</item>
<item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
<!-- Dialog attributes -->
- <item name="dialogTheme">@android:style/Theme.Quantum.Dialog</item>
+ <item name="dialogTheme">@style/Theme.Quantum.Dialog</item>
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
<!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@android:style/Theme.Quantum.Dialog.Alert</item>
- <item name="alertDialogStyle">@android:style/AlertDialog.Quantum</item>
+ <item name="alertDialogTheme">@style/Theme.Quantum.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Quantum</item>
<item name="alertDialogCenterButtons">false</item>
- <item name="alertDialogIcon">@android:drawable/ic_dialog_alert_holo_dark</item>
+ <item name="alertDialogIcon">@drawable/ic_dialog_alert_holo_dark</item>
<!-- Presentation attributes -->
- <item name="presentationTheme">@android:style/Theme.Quantum.Dialog.Presentation</item>
+ <item name="presentationTheme">@style/Theme.Quantum.Dialog.Presentation</item>
<!-- Toast attributes -->
- <item name="toastFrameBackground">@android:drawable/toast_frame</item>
+ <item name="toastFrameBackground">@drawable/toast_frame</item>
<!-- Panel attributes -->
- <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_dark</item>
- <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item>
+ <item name="panelBackground">@drawable/menu_hardkey_panel_holo_dark</item>
+ <item name="panelFullBackground">@drawable/menu_background_fill_parent_width</item>
<!-- These three attributes do not seems to be used by the framework. Declared public though -->
<item name="panelColorBackground">#000</item>
- <item name="panelColorForeground">?android:attr/textColorPrimary</item>
- <item name="panelTextAppearance">?android:attr/textAppearance</item>
+ <item name="panelColorForeground">?attr/textColorPrimary</item>
+ <item name="panelTextAppearance">?attr/textAppearance</item>
<item name="panelMenuIsCompact">true</item>
<item name="panelMenuListWidth">250dip</item>
- <item name="panelMenuListTheme">@android:style/Theme.Quantum.CompactMenu</item>
+ <item name="panelMenuListTheme">@style/Theme.Quantum.CompactMenu</item>
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">300</item>
<item name="scrollbarSize">10dip</item>
- <item name="scrollbarThumbHorizontal">@android:drawable/scrollbar_handle_holo_dark</item>
- <item name="scrollbarThumbVertical">@android:drawable/scrollbar_handle_holo_dark</item>
+ <item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_holo_dark</item>
+ <item name="scrollbarThumbVertical">@drawable/scrollbar_handle_holo_dark</item>
<item name="scrollbarTrackHorizontal">@null</item>
<item name="scrollbarTrackVertical">@null</item>
<!-- Text selection handle attributes -->
- <item name="textSelectHandleLeft">@android:drawable/text_select_handle_left</item>
- <item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
- <item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
- <item name="textSelectHandleWindowStyle">@android:style/Widget.Quantum.TextSelectHandle</item>
- <item name="textSuggestionsWindowStyle">@android:style/Widget.Quantum.TextSuggestionsPopupWindow</item>
- <item name="textCursorDrawable">@android:drawable/text_cursor_holo_dark</item>
+ <item name="textSelectHandleLeft">@drawable/text_select_handle_left</item>
+ <item name="textSelectHandleRight">@drawable/text_select_handle_right</item>
+ <item name="textSelectHandle">@drawable/text_select_handle_middle</item>
+ <item name="textSelectHandleWindowStyle">@style/Widget.Quantum.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@style/Widget.Quantum.TextSuggestionsPopupWindow</item>
+ <item name="textCursorDrawable">@drawable/text_cursor_holo_dark</item>
<!-- Widget styles -->
- <item name="absListViewStyle">@android:style/Widget.Quantum.AbsListView</item>
- <item name="autoCompleteTextViewStyle">@android:style/Widget.Quantum.AutoCompleteTextView</item>
- <item name="checkboxStyle">@android:style/Widget.Quantum.CompoundButton.CheckBox</item>
- <item name="checkedTextViewStyle">@android:style/Widget.Quantum.CheckedTextView</item>
- <item name="dropDownListViewStyle">@android:style/Widget.Quantum.ListView.DropDown</item>
- <item name="editTextStyle">@android:style/Widget.Quantum.EditText</item>
- <item name="expandableListViewStyle">@android:style/Widget.Quantum.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@android:style/Widget.Quantum.ExpandableListView.White</item>
- <item name="fastScrollStyle">@android:style/Widget.Quantum.FastScroll</item>
- <item name="galleryStyle">@android:style/Widget.Quantum.Gallery</item>
- <item name="gestureOverlayViewStyle">@android:style/Widget.Quantum.GestureOverlayView</item>
- <item name="gridViewStyle">@android:style/Widget.Quantum.GridView</item>
- <item name="imageButtonStyle">@android:style/Widget.Quantum.ImageButton</item>
- <item name="imageWellStyle">@android:style/Widget.Quantum.ImageWell</item>
- <item name="listViewStyle">@android:style/Widget.Quantum.ListView</item>
- <item name="listViewWhiteStyle">@android:style/Widget.Quantum.ListView.White</item>
- <item name="popupWindowStyle">@android:style/Widget.Quantum.PopupWindow</item>
- <item name="progressBarStyle">@android:style/Widget.Quantum.ProgressBar</item>
- <item name="progressBarStyleHorizontal">@android:style/Widget.Quantum.ProgressBar.Horizontal</item>
- <item name="progressBarStyleSmall">@android:style/Widget.Quantum.ProgressBar.Small</item>
- <item name="progressBarStyleSmallTitle">@android:style/Widget.Quantum.ProgressBar.Small.Title</item>
- <item name="progressBarStyleLarge">@android:style/Widget.Quantum.ProgressBar.Large</item>
- <item name="progressBarStyleInverse">@android:style/Widget.Quantum.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@android:style/Widget.Quantum.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@android:style/Widget.Quantum.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@android:style/Widget.Quantum.SeekBar</item>
- <item name="ratingBarStyle">@android:style/Widget.Quantum.RatingBar</item>
- <item name="ratingBarStyleIndicator">@android:style/Widget.Quantum.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@android:style/Widget.Quantum.RatingBar.Small</item>
- <item name="radioButtonStyle">@android:style/Widget.Quantum.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@android:style/Widget.Quantum.ScrollView</item>
- <item name="horizontalScrollViewStyle">@android:style/Widget.Quantum.HorizontalScrollView</item>
- <item name="spinnerStyle">?android:attr/dropDownSpinnerStyle</item>
- <item name="dropDownSpinnerStyle">@android:style/Widget.Quantum.Spinner.DropDown</item>
- <item name="starStyle">@android:style/Widget.Quantum.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@android:style/Widget.Quantum.TabWidget</item>
- <item name="textViewStyle">@android:style/Widget.Quantum.TextView</item>
- <item name="errorMessageBackground">@android:drawable/popup_inline_error_holo_dark</item>
- <item name="errorMessageAboveBackground">@android:drawable/popup_inline_error_above_holo_dark</item>
- <item name="webTextViewStyle">@android:style/Widget.Quantum.WebTextView</item>
- <item name="webViewStyle">@android:style/Widget.Quantum.WebView</item>
- <item name="dropDownItemStyle">@android:style/Widget.Quantum.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@android:style/Widget.Quantum.DropDownItem.Spinner</item>
- <item name="spinnerItemStyle">@android:style/Widget.Quantum.TextView.SpinnerItem</item>
- <item name="dropDownHintAppearance">@android:style/TextAppearance.Quantum.Widget.DropDownHint</item>
- <item name="keyboardViewStyle">@android:style/Widget.Quantum.KeyboardView</item>
- <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.Quantum.QuickContactBadge.WindowSmall</item>
- <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.Quantum.QuickContactBadge.WindowMedium</item>
- <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.Quantum.QuickContactBadge.WindowLarge</item>
- <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.Quantum.QuickContactBadgeSmall.WindowSmall</item>
- <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.Quantum.QuickContactBadgeSmall.WindowMedium</item>
- <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@android:style/Widget.Quantum.ListPopupWindow</item>
- <item name="popupMenuStyle">@android:style/Widget.Quantum.PopupMenu</item>
- <item name="stackViewStyle">@android:style/Widget.Quantum.StackView</item>
- <item name="activityChooserViewStyle">@android:style/Widget.Quantum.ActivityChooserView</item>
- <item name="fragmentBreadCrumbsStyle">@android:style/Widget.Quantum.FragmentBreadCrumbs</item>
+ <item name="absListViewStyle">@style/Widget.Quantum.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@style/Widget.Quantum.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@style/Widget.Quantum.CompoundButton.CheckBox</item>
+ <item name="checkedTextViewStyle">@style/Widget.Quantum.CheckedTextView</item>
+ <item name="dropDownListViewStyle">@style/Widget.Quantum.ListView.DropDown</item>
+ <item name="editTextStyle">@style/Widget.Quantum.EditText</item>
+ <item name="expandableListViewStyle">@style/Widget.Quantum.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@style/Widget.Quantum.ExpandableListView.White</item>
+ <item name="fastScrollStyle">@style/Widget.Quantum.FastScroll</item>
+ <item name="galleryStyle">@style/Widget.Quantum.Gallery</item>
+ <item name="gestureOverlayViewStyle">@style/Widget.Quantum.GestureOverlayView</item>
+ <item name="gridViewStyle">@style/Widget.Quantum.GridView</item>
+ <item name="imageButtonStyle">@style/Widget.Quantum.ImageButton</item>
+ <item name="imageWellStyle">@style/Widget.Quantum.ImageWell</item>
+ <item name="listViewStyle">@style/Widget.Quantum.ListView</item>
+ <item name="listViewWhiteStyle">@style/Widget.Quantum.ListView.White</item>
+ <item name="popupWindowStyle">@style/Widget.Quantum.PopupWindow</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@style/Widget.Quantum.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@style/Widget.Quantum.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@style/Widget.Quantum.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@style/Widget.Quantum.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@style/Widget.Quantum.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@style/Widget.Quantum.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@style/Widget.Quantum.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@style/Widget.Quantum.SeekBar</item>
+ <item name="ratingBarStyle">@style/Widget.Quantum.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@style/Widget.Quantum.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@style/Widget.Quantum.RatingBar.Small</item>
+ <item name="radioButtonStyle">@style/Widget.Quantum.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@style/Widget.Quantum.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@style/Widget.Quantum.HorizontalScrollView</item>
+ <item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
+ <item name="dropDownSpinnerStyle">@style/Widget.Quantum.Spinner.DropDown</item>
+ <item name="starStyle">@style/Widget.Quantum.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@style/Widget.Quantum.TabWidget</item>
+ <item name="textViewStyle">@style/Widget.Quantum.TextView</item>
+ <item name="errorMessageBackground">@drawable/popup_inline_error_holo_dark</item>
+ <item name="errorMessageAboveBackground">@drawable/popup_inline_error_above_holo_dark</item>
+ <item name="webTextViewStyle">@style/Widget.Quantum.WebTextView</item>
+ <item name="webViewStyle">@style/Widget.Quantum.WebView</item>
+ <item name="dropDownItemStyle">@style/Widget.Quantum.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@style/Widget.Quantum.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@style/Widget.Quantum.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@style/TextAppearance.Quantum.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@style/Widget.Quantum.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@style/Widget.Quantum.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@style/Widget.Quantum.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@style/Widget.Quantum.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.Quantum.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.Quantum.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@style/Widget.Quantum.ListPopupWindow</item>
+ <item name="popupMenuStyle">@style/Widget.Quantum.PopupMenu</item>
+ <item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
+ <item name="activityChooserViewStyle">@style/Widget.Quantum.ActivityChooserView</item>
+ <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.FragmentBreadCrumbs</item>
<!-- Preference styles -->
- <item name="preferenceScreenStyle">@android:style/Preference.Quantum.PreferenceScreen</item>
+ <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item>
- <item name="preferenceCategoryStyle">@android:style/Preference.Quantum.Category</item>
- <item name="preferenceStyle">@android:style/Preference.Quantum</item>
- <item name="preferenceInformationStyle">@android:style/Preference.Quantum.Information</item>
- <item name="checkBoxPreferenceStyle">@android:style/Preference.Quantum.CheckBoxPreference</item>
- <item name="switchPreferenceStyle">@android:style/Preference.Quantum.SwitchPreference</item>
- <item name="yesNoPreferenceStyle">@android:style/Preference.Quantum.DialogPreference.YesNoPreference</item>
- <item name="dialogPreferenceStyle">@android:style/Preference.Quantum.DialogPreference</item>
- <item name="editTextPreferenceStyle">@android:style/Preference.Quantum.DialogPreference.EditTextPreference</item>
- <item name="ringtonePreferenceStyle">@android:style/Preference.Quantum.RingtonePreference</item>
- <item name="preferenceLayoutChild">@android:layout/preference_child_holo</item>
- <item name="detailsElementBackground">@android:drawable/panel_bg_holo_dark</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item>
+ <item name="preferenceStyle">@style/Preference.Quantum</item>
+ <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.Quantum.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@style/Preference.Quantum.SwitchPreference</item>
+ <item name="yesNoPreferenceStyle">@style/Preference.Quantum.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item>
+ <item name="preferenceLayoutChild">@layout/preference_child_holo</item>
+ <item name="detailsElementBackground">@drawable/panel_bg_holo_dark</item>
<!-- Search widget styles -->
- <item name="searchWidgetCorpusItemBackground">@android:color/search_widget_corpus_item_background</item>
+ <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
<!-- Action bar styles -->
- <item name="actionDropDownStyle">@android:style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@android:style/Widget.Quantum.ActionButton</item>
- <item name="actionOverflowButtonStyle">@android:style/Widget.Quantum.ActionButton.Overflow</item>
- <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
- <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_dark</item>
- <item name="actionModeCloseDrawable">@android:drawable/ic_cab_done_holo_dark</item>
+ <item name="actionDropDownStyle">@style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@style/Widget.Quantum.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.Quantum.ActionButton.Overflow</item>
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_dark</item>
+ <item name="actionModeCloseDrawable">@drawable/ic_cab_done_holo_dark</item>
<item name="actionBarTabStyle">@style/Widget.Quantum.ActionBar.TabView</item>
<item name="actionBarTabBarStyle">@style/Widget.Quantum.ActionBar.TabBar</item>
<item name="actionBarTabTextStyle">@style/Widget.Quantum.ActionBar.TabText</item>
<item name="actionModeStyle">@style/Widget.Quantum.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Quantum.ActionButton.CloseMode</item>
- <item name="actionBarStyle">@android:style/Widget.Quantum.ActionBar</item>
+ <item name="actionBarStyle">@style/Widget.Quantum.ActionBar</item>
<item name="actionBarSize">@dimen/action_bar_default_height</item>
- <item name="actionModePopupWindowStyle">@android:style/Widget.Quantum.PopupWindow.ActionMode</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.Quantum.PopupWindow.ActionMode</item>
<item name="actionBarWidgetTheme">@null</item>
- <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item>
- <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_dark</item>
- <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_dark</item>
- <item name="actionModeSelectAllDrawable">@android:drawable/ic_menu_selectall_holo_dark</item>
- <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_dark</item>
- <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_dark</item>
- <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_dark</item>
+ <item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_dark</item>
+ <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_dark</item>
+ <item name="actionModePasteDrawable">@drawable/ic_menu_paste_holo_dark</item>
+ <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_holo_dark</item>
+ <item name="actionModeShareDrawable">@drawable/ic_menu_share_holo_dark</item>
+ <item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_dark</item>
+ <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_dark</item>
- <item name="dividerVertical">?android:attr/listDivider</item>
- <item name="dividerHorizontal">?android:attr/listDivider</item>
- <item name="buttonBarStyle">@android:style/Quantum.ButtonBar</item>
- <item name="buttonBarButtonStyle">?android:attr/borderlessButtonStyle</item>
- <item name="segmentedButtonStyle">@android:style/Quantum.SegmentedButton</item>
+ <item name="dividerVertical">?attr/listDivider</item>
+ <item name="dividerHorizontal">?attr/listDivider</item>
+ <item name="buttonBarStyle">@style/Quantum.ButtonBar</item>
+ <item name="buttonBarButtonStyle">?attr/borderlessButtonStyle</item>
+ <item name="segmentedButtonStyle">@style/Quantum.SegmentedButton</item>
<!-- SearchView attributes -->
- <item name="searchDropdownBackground">@android:drawable/search_dropdown_dark</item>
+ <item name="searchDropdownBackground">@drawable/search_dropdown_dark</item>
<item name="searchDialogTheme">@style/Theme.Quantum.SearchBar</item>
<!-- PreferenceFrameLayout attributes -->
- <item name="preferenceFrameLayoutStyle">@android:style/Widget.Quantum.PreferenceFrameLayout</item>
+ <item name="preferenceFrameLayoutStyle">@style/Widget.Quantum.PreferenceFrameLayout</item>
<!-- NumberPicker style-->
<item name="numberPickerStyle">@style/Widget.Quantum.NumberPicker</item>
@@ -344,7 +345,7 @@
<item name="timePickerStyle">@style/Widget.Quantum.TimePicker</item>
<!-- TimePicker background color -->
- <item name="timePickerHeaderBackgroundColor">@android:color/timepicker_default_background_holo_dark</item>
+ <item name="timePickerHeaderBackgroundColor">@color/timepicker_default_background_quantum_dark</item>
<!-- TimePicker Header time label text appearance -->
<item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.TimeLabel</item>
@@ -353,25 +354,25 @@
<item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.TimePicker.AmPmLabel</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@android:style/Theme.Quantum.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">@style/Theme.Quantum.Dialog.TimePicker</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Quantum.DatePicker</item>
- <item name="fastScrollThumbDrawable">@android:drawable/fastscroll_thumb_holo</item>
- <item name="fastScrollPreviewBackgroundLeft">@android:drawable/fastscroll_label_left_holo_dark</item>
- <item name="fastScrollPreviewBackgroundRight">@android:drawable/fastscroll_label_right_holo_dark</item>
- <item name="fastScrollTrackDrawable">@android:drawable/fastscroll_track_holo_dark</item>
+ <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item>
+ <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_holo_dark</item>
<item name="fastScrollOverlayPosition">atThumb</item>
</style>
<!-- Quantum Paper theme (light version). -->
<style name="Theme.Quantum.Light" parent="Theme.Light">
- <item name="colorForeground">@android:color/bright_foreground_holo_light</item>
- <item name="colorForegroundInverse">@android:color/bright_foreground_inverse_holo_light</item>
- <item name="colorBackground">@android:color/background_holo_light</item>
- <item name="colorBackgroundCacheHint">@android:drawable/background_cache_hint_selector_holo_light</item>
+ <item name="colorForeground">@color/bright_foreground_quantum_light</item>
+ <item name="colorForegroundInverse">@color/bright_foreground_quantum_dark</item>
+ <item name="colorBackground">@color/background_quantum_light</item>
+ <item name="colorBackgroundCacheHint">@drawable/background_cache_hint_selector_quantum_light</item>
<item name="disabledAlpha">0.5</item>
<item name="backgroundDimAmount">0.6</item>
@@ -382,72 +383,72 @@
<item name="colorActivatedHighlight">@color/holo_blue_dark</item>
<!-- Text styles -->
- <item name="textAppearance">@android:style/TextAppearance.Quantum.Light</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.Quantum.Light.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.Light</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Light.Inverse</item>
- <item name="textColorPrimary">@android:color/primary_text_holo_light</item>
- <item name="textColorSecondary">@android:color/secondary_text_holo_light</item>
- <item name="textColorTertiary">@android:color/tertiary_text_holo_light</item>
- <item name="textColorPrimaryInverse">@android:color/primary_text_holo_dark</item>
- <item name="textColorSecondaryInverse">@android:color/secondary_text_holo_dark</item>
- <item name="textColorTertiaryInverse">@android:color/tertiary_text_holo_dark</item>
- <item name="textColorPrimaryDisableOnly">@android:color/primary_text_disable_only_holo_light</item>
- <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_disable_only_holo_dark</item>
- <item name="textColorPrimaryNoDisable">@android:color/primary_text_nodisable_holo_light</item>
- <item name="textColorSecondaryNoDisable">@android:color/secondary_text_nodisable_holo_light</item>
- <item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_nodisable_holo_dark</item>
- <item name="textColorSecondaryInverseNoDisable">@android:color/secondary_text_nodisable_holo_dark</item>
- <item name="textColorHint">@android:color/hint_foreground_holo_light</item>
- <item name="textColorHintInverse">@android:color/hint_foreground_holo_dark</item>
- <item name="textColorSearchUrl">@android:color/search_url_text_holo</item>
- <item name="textColorHighlight">@android:color/highlighted_text_holo_light</item>
- <item name="textColorHighlightInverse">@android:color/highlighted_text_holo_dark</item>
- <item name="textColorLink">@android:color/holo_blue_light</item>
- <item name="textColorLinkInverse">@android:color/holo_blue_light</item>
- <item name="textColorAlertDialogListItem">@android:color/primary_text_holo_light</item>
+ <item name="textColorPrimary">@color/primary_text_quantum_light</item>
+ <item name="textColorSecondary">@color/secondary_text_quantum_light</item>
+ <item name="textColorTertiary">@color/tertiary_text_quantum_light</item>
+ <item name="textColorPrimaryInverse">@color/primary_text_quantum_dark</item>
+ <item name="textColorSecondaryInverse">@color/secondary_text_quantum_dark</item>
+ <item name="textColorTertiaryInverse">@color/tertiary_text_quantum_dark</item>
+ <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_quantum_light</item>
+ <item name="textColorPrimaryInverseDisableOnly">@color/primary_text_disable_only_quantum_dark</item>
+ <item name="textColorPrimaryNoDisable">@color/primary_text_nodisable_quantum_light</item>
+ <item name="textColorSecondaryNoDisable">@color/secondary_text_nodisable_quantum_light</item>
+ <item name="textColorPrimaryInverseNoDisable">@color/primary_text_nodisable_quantum_dark</item>
+ <item name="textColorSecondaryInverseNoDisable">@color/secondary_text_nodisable_quantum_dark</item>
+ <item name="textColorHint">@color/hint_foreground_quantum_light</item>
+ <item name="textColorHintInverse">@color/hint_foreground_quantum_dark</item>
+ <item name="textColorSearchUrl">@color/search_url_text_quantum_light</item>
+ <item name="textColorHighlight">@color/highlighted_text_quantum_light</item>
+ <item name="textColorHighlightInverse">@color/highlighted_text_quantum_dark</item>
+ <item name="textColorLink">@color/holo_blue_light</item>
+ <item name="textColorLinkInverse">@color/holo_blue_light</item>
+ <item name="textColorAlertDialogListItem">@color/primary_text_quantum_light</item>
- <item name="textAppearanceLarge">@android:style/TextAppearance.Quantum.Light.Large</item>
- <item name="textAppearanceMedium">@android:style/TextAppearance.Quantum.Light.Medium</item>
- <item name="textAppearanceSmall">@android:style/TextAppearance.Quantum.Light.Small</item>
- <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Quantum.Light.Large.Inverse</item>
- <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Quantum.Light.Medium.Inverse</item>
- <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Quantum.Light.Small.Inverse</item>
- <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.Quantum.Light.SearchResult.Title</item>
- <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.Quantum.Light.SearchResult.Subtitle</item>
+ <item name="textAppearanceLarge">@style/TextAppearance.Quantum.Light.Large</item>
+ <item name="textAppearanceMedium">@style/TextAppearance.Quantum.Light.Medium</item>
+ <item name="textAppearanceSmall">@style/TextAppearance.Quantum.Light.Small</item>
+ <item name="textAppearanceLargeInverse">@style/TextAppearance.Quantum.Light.Large.Inverse</item>
+ <item name="textAppearanceMediumInverse">@style/TextAppearance.Quantum.Light.Medium.Inverse</item>
+ <item name="textAppearanceSmallInverse">@style/TextAppearance.Quantum.Light.Small.Inverse</item>
+ <item name="textAppearanceSearchResultTitle">@style/TextAppearance.Quantum.Light.SearchResult.Title</item>
+ <item name="textAppearanceSearchResultSubtitle">@style/TextAppearance.Quantum.Light.SearchResult.Subtitle</item>
- <item name="textAppearanceButton">@android:style/TextAppearance.Quantum.Light.Widget.Button</item>
+ <item name="textAppearanceButton">@style/TextAppearance.Quantum.Light.Widget.Button</item>
- <item name="editTextColor">?android:attr/textColorPrimary</item>
- <item name="editTextBackground">@android:drawable/edit_text_holo_light</item>
+ <item name="editTextColor">?attr/textColorPrimary</item>
+ <item name="editTextBackground">@drawable/edit_text_holo_light</item>
- <item name="candidatesTextStyleSpans">@android:string/candidates_style</item>
+ <item name="candidatesTextStyleSpans">@string/candidates_style</item>
- <item name="textCheckMark">@android:drawable/indicator_check_mark_light</item>
- <item name="textCheckMarkInverse">@android:drawable/indicator_check_mark_dark</item>
+ <item name="textCheckMark">@drawable/indicator_check_mark_light</item>
+ <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item>
- <item name="textAppearanceLargePopupMenu">@android:style/TextAppearance.Quantum.Light.Widget.PopupMenu.Large</item>
- <item name="textAppearanceSmallPopupMenu">@android:style/TextAppearance.Quantum.Light.Widget.PopupMenu.Small</item>
+ <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Quantum.Light.Widget.PopupMenu.Large</item>
+ <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Quantum.Light.Widget.PopupMenu.Small</item>
<!-- Button styles -->
- <item name="buttonStyle">@android:style/Widget.Quantum.Light.Button</item>
+ <item name="buttonStyle">@style/Widget.Quantum.Light.Button</item>
- <item name="buttonStyleSmall">@android:style/Widget.Quantum.Light.Button.Small</item>
- <item name="buttonStyleInset">@android:style/Widget.Quantum.Light.Button.Inset</item>
+ <item name="buttonStyleSmall">@style/Widget.Quantum.Light.Button.Small</item>
+ <item name="buttonStyleInset">@style/Widget.Quantum.Light.Button.Inset</item>
- <item name="buttonStyleToggle">@android:style/Widget.Quantum.Light.Button.Toggle</item>
- <item name="switchStyle">@android:style/Widget.Quantum.Light.CompoundButton.Switch</item>
- <item name="mediaRouteButtonStyle">@android:style/Widget.Quantum.Light.MediaRouteButton</item>
+ <item name="buttonStyleToggle">@style/Widget.Quantum.Light.Button.Toggle</item>
+ <item name="switchStyle">@style/Widget.Quantum.Light.CompoundButton.Switch</item>
+ <item name="mediaRouteButtonStyle">@style/Widget.Quantum.Light.MediaRouteButton</item>
- <item name="selectableItemBackground">@android:drawable/item_background_holo_light</item>
- <item name="borderlessButtonStyle">@android:style/Widget.Quantum.Light.Button.Borderless</item>
- <item name="homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
+ <item name="selectableItemBackground">@drawable/item_background_quantum_light</item>
+ <item name="borderlessButtonStyle">@style/Widget.Quantum.Light.Button.Borderless</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_holo_light</item>
<!-- List attributes -->
<item name="listPreferredItemHeight">64dip</item>
<item name="listPreferredItemHeightSmall">48dip</item>
<item name="listPreferredItemHeightLarge">80dip</item>
- <item name="dropdownListPreferredItemHeight">?android:attr/listPreferredItemHeightSmall</item>
- <item name="textAppearanceListItemSmall">?android:attr/textAppearanceMedium</item>
+ <item name="dropdownListPreferredItemHeight">?attr/listPreferredItemHeightSmall</item>
+ <item name="textAppearanceListItemSmall">?attr/textAppearanceMedium</item>
<item name="listPreferredItemPaddingLeft">8dip</item>
<item name="listPreferredItemPaddingRight">8dip</item>
<item name="listPreferredItemPaddingStart">8dip</item>
@@ -456,206 +457,207 @@
<!-- @hide -->
<item name="searchResultListItemHeight">58dip</item>
<item name="listDivider">@drawable/list_divider_holo_light</item>
- <item name="listSeparatorTextViewStyle">@android:style/Widget.Quantum.Light.TextView.ListSeparator</item>
+ <item name="listSeparatorTextViewStyle">@style/Widget.Quantum.Light.TextView.ListSeparator</item>
- <item name="listChoiceIndicatorSingle">@android:drawable/btn_radio_holo_light</item>
- <item name="listChoiceIndicatorMultiple">@android:drawable/btn_check_holo_light</item>
+ <item name="listChoiceIndicatorSingle">@drawable/btn_radio_holo_light</item>
+ <item name="listChoiceIndicatorMultiple">@drawable/btn_check_holo_light</item>
- <item name="listChoiceBackgroundIndicator">@android:drawable/list_selector_holo_light</item>
+ <item name="listChoiceBackgroundIndicator">@drawable/list_selector_quantum_light</item>
- <item name="activatedBackgroundIndicator">@android:drawable/activated_background_holo_light</item>
+ <item name="activatedBackgroundIndicator">@drawable/activated_background_holo_light</item>
<item name="expandableListPreferredItemPaddingLeft">40dip</item>
- <item name="expandableListPreferredChildPaddingLeft">?android:attr/expandableListPreferredItemPaddingLeft</item>
+ <item name="expandableListPreferredChildPaddingLeft">?attr/expandableListPreferredItemPaddingLeft</item>
<item name="expandableListPreferredItemIndicatorLeft">3dip</item>
<item name="expandableListPreferredItemIndicatorRight">0dip</item>
- <item name="expandableListPreferredChildIndicatorLeft">?android:attr/expandableListPreferredItemIndicatorLeft</item>
- <item name="expandableListPreferredChildIndicatorRight">?android:attr/expandableListPreferredItemIndicatorRight</item>
+ <item name="expandableListPreferredChildIndicatorLeft">?attr/expandableListPreferredItemIndicatorLeft</item>
+ <item name="expandableListPreferredChildIndicatorRight">?attr/expandableListPreferredItemIndicatorRight</item>
- <item name="listDividerAlertDialog">@android:drawable/list_divider_holo_light</item>
- <item name="findOnPageNextDrawable">@android:drawable/ic_find_next_holo_light</item>
- <item name="findOnPagePreviousDrawable">@android:drawable/ic_find_previous_holo_light</item>
+ <item name="listDividerAlertDialog">@drawable/list_divider_holo_light</item>
+ <item name="findOnPageNextDrawable">@drawable/ic_find_next_holo_light</item>
+ <item name="findOnPagePreviousDrawable">@drawable/ic_find_previous_holo_light</item>
<!-- Gallery attributes -->
- <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
+ <item name="galleryItemBackground">@drawable/gallery_item_background</item>
<!-- Window attributes -->
+ <item name="windowBackground">@color/background_quantum_light</item>
<item name="windowFrame">@null</item>
<item name="windowNoTitle">false</item>
<item name="windowFullscreen">false</item>
<item name="windowOverscan">false</item>
<item name="windowIsFloating">false</item>
- <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
+ <item name="windowContentOverlay">@drawable/ab_solid_shadow_holo</item>
<item name="windowShowWallpaper">false</item>
- <item name="windowTitleStyle">@android:style/WindowTitle.Quantum</item>
+ <item name="windowTitleStyle">@style/WindowTitle.Quantum</item>
<item name="windowTitleSize">25dip</item>
- <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground.Quantum</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.Quantum.Activity</item>
- <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+ <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Quantum</item>
+ <item name="windowAnimationStyle">@style/Animation.Quantum.Activity</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
<!-- Dialog attributes -->
- <item name="dialogTheme">@android:style/Theme.Quantum.Light.Dialog</item>
+ <item name="dialogTheme">@style/Theme.Quantum.Light.Dialog</item>
<item name="dialogTitleIconsDecorLayout">@layout/dialog_title_icons_holo</item>
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_holo</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_holo</item>
<!-- AlertDialog attributes -->
- <item name="alertDialogTheme">@android:style/Theme.Quantum.Light.Dialog.Alert</item>
- <item name="alertDialogStyle">@android:style/AlertDialog.Quantum.Light</item>
+ <item name="alertDialogTheme">@style/Theme.Quantum.Light.Dialog.Alert</item>
+ <item name="alertDialogStyle">@style/AlertDialog.Quantum.Light</item>
<item name="alertDialogCenterButtons">false</item>
- <item name="alertDialogIcon">@android:drawable/ic_dialog_alert_holo_light</item>
+ <item name="alertDialogIcon">@drawable/ic_dialog_alert_holo_light</item>
<!-- Presentation attributes -->
- <item name="presentationTheme">@android:style/Theme.Quantum.Light.Dialog.Presentation</item>
+ <item name="presentationTheme">@style/Theme.Quantum.Light.Dialog.Presentation</item>
<!-- Toast attributes -->
- <item name="toastFrameBackground">@android:drawable/toast_frame</item>
+ <item name="toastFrameBackground">@drawable/toast_frame</item>
<!-- Panel attributes -->
- <item name="panelBackground">@android:drawable/menu_hardkey_panel_holo_light</item>
- <item name="panelFullBackground">@android:drawable/menu_background_fill_parent_width</item>
+ <item name="panelBackground">@drawable/menu_hardkey_panel_holo_light</item>
+ <item name="panelFullBackground">@drawable/menu_background_fill_parent_width</item>
<!-- These three attributes do not seems to be used by the framework. Declared public though -->
<item name="panelColorBackground">#000</item>
- <item name="panelColorForeground">?android:attr/textColorPrimary</item>
- <item name="panelTextAppearance">?android:attr/textAppearance</item>
+ <item name="panelColorForeground">?attr/textColorPrimary</item>
+ <item name="panelTextAppearance">?attr/textAppearance</item>
<item name="panelMenuIsCompact">true</item>
<item name="panelMenuListWidth">250dip</item>
- <item name="panelMenuListTheme">@android:style/Theme.Quantum.Light.CompactMenu</item>
+ <item name="panelMenuListTheme">@style/Theme.Quantum.Light.CompactMenu</item>
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">300</item>
<item name="scrollbarSize">10dip</item>
- <item name="scrollbarThumbHorizontal">@android:drawable/scrollbar_handle_holo_light</item>
- <item name="scrollbarThumbVertical">@android:drawable/scrollbar_handle_holo_light</item>
+ <item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_holo_light</item>
+ <item name="scrollbarThumbVertical">@drawable/scrollbar_handle_holo_light</item>
<item name="scrollbarTrackHorizontal">@null</item>
<item name="scrollbarTrackVertical">@null</item>
<!-- Text selection handle attributes -->
- <item name="textSelectHandleLeft">@android:drawable/text_select_handle_left</item>
- <item name="textSelectHandleRight">@android:drawable/text_select_handle_right</item>
- <item name="textSelectHandle">@android:drawable/text_select_handle_middle</item>
- <item name="textSelectHandleWindowStyle">@android:style/Widget.Quantum.TextSelectHandle</item>
- <item name="textSuggestionsWindowStyle">@android:style/Widget.Quantum.Light.TextSuggestionsPopupWindow</item>
- <item name="textCursorDrawable">@android:drawable/text_cursor_holo_light</item>
+ <item name="textSelectHandleLeft">@drawable/text_select_handle_left</item>
+ <item name="textSelectHandleRight">@drawable/text_select_handle_right</item>
+ <item name="textSelectHandle">@drawable/text_select_handle_middle</item>
+ <item name="textSelectHandleWindowStyle">@style/Widget.Quantum.TextSelectHandle</item>
+ <item name="textSuggestionsWindowStyle">@style/Widget.Quantum.Light.TextSuggestionsPopupWindow</item>
+ <item name="textCursorDrawable">@drawable/text_cursor_holo_light</item>
<!-- Widget styles -->
- <item name="absListViewStyle">@android:style/Widget.Quantum.Light.AbsListView</item>
- <item name="autoCompleteTextViewStyle">@android:style/Widget.Quantum.Light.AutoCompleteTextView</item>
- <item name="checkboxStyle">@android:style/Widget.Quantum.Light.CompoundButton.CheckBox</item>
- <item name="checkedTextViewStyle">@android:style/Widget.Quantum.Light.CheckedTextView</item>
- <item name="dropDownListViewStyle">@android:style/Widget.Quantum.ListView.DropDown</item>
- <item name="editTextStyle">@android:style/Widget.Quantum.Light.EditText</item>
- <item name="expandableListViewStyle">@android:style/Widget.Quantum.Light.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@android:style/Widget.Quantum.Light.ExpandableListView.White</item>
- <item name="fastScrollStyle">@android:style/Widget.Quantum.Light.FastScroll</item>
- <item name="galleryStyle">@android:style/Widget.Quantum.Light.Gallery</item>
- <item name="gestureOverlayViewStyle">@android:style/Widget.Quantum.Light.GestureOverlayView</item>
- <item name="gridViewStyle">@android:style/Widget.Quantum.Light.GridView</item>
- <item name="imageButtonStyle">@android:style/Widget.Quantum.Light.ImageButton</item>
- <item name="imageWellStyle">@android:style/Widget.Quantum.Light.ImageWell</item>
- <item name="listViewStyle">@android:style/Widget.Quantum.Light.ListView</item>
- <item name="listViewWhiteStyle">@android:style/Widget.Quantum.Light.ListView.White</item>
- <item name="popupWindowStyle">@android:style/Widget.Quantum.Light.PopupWindow</item>
- <item name="progressBarStyle">@android:style/Widget.Quantum.Light.ProgressBar</item>
- <item name="progressBarStyleHorizontal">@android:style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
- <item name="progressBarStyleSmall">@android:style/Widget.Quantum.Light.ProgressBar.Small</item>
- <item name="progressBarStyleSmallTitle">@android:style/Widget.Quantum.Light.ProgressBar.Small.Title</item>
- <item name="progressBarStyleLarge">@android:style/Widget.Quantum.Light.ProgressBar.Large</item>
- <item name="progressBarStyleInverse">@android:style/Widget.Quantum.Light.ProgressBar.Inverse</item>
- <item name="progressBarStyleSmallInverse">@android:style/Widget.Quantum.Light.ProgressBar.Small.Inverse</item>
- <item name="progressBarStyleLargeInverse">@android:style/Widget.Quantum.Light.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@android:style/Widget.Quantum.Light.SeekBar</item>
- <item name="ratingBarStyle">@android:style/Widget.Quantum.Light.RatingBar</item>
- <item name="ratingBarStyleIndicator">@android:style/Widget.Quantum.Light.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@android:style/Widget.Quantum.Light.RatingBar.Small</item>
- <item name="radioButtonStyle">@android:style/Widget.Quantum.Light.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@android:style/Widget.Quantum.Light.ScrollView</item>
- <item name="horizontalScrollViewStyle">@android:style/Widget.Quantum.Light.HorizontalScrollView</item>
- <item name="spinnerStyle">?android:attr/dropDownSpinnerStyle</item>
- <item name="dropDownSpinnerStyle">@android:style/Widget.Quantum.Light.Spinner.DropDown</item>
- <item name="starStyle">@android:style/Widget.Quantum.Light.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@android:style/Widget.Quantum.Light.TabWidget</item>
- <item name="textViewStyle">@android:style/Widget.Quantum.Light.TextView</item>
- <item name="errorMessageBackground">@android:drawable/popup_inline_error_holo_light</item>
- <item name="errorMessageAboveBackground">@android:drawable/popup_inline_error_above_holo_light</item>
- <item name="webTextViewStyle">@android:style/Widget.Quantum.Light.WebTextView</item>
- <item name="webViewStyle">@android:style/Widget.Quantum.Light.WebView</item>
- <item name="dropDownItemStyle">@android:style/Widget.Quantum.Light.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@android:style/Widget.Quantum.Light.DropDownItem.Spinner</item>
- <item name="spinnerItemStyle">@android:style/Widget.Quantum.TextView.SpinnerItem</item>
- <item name="dropDownHintAppearance">@android:style/TextAppearance.Quantum.Widget.DropDownHint</item>
- <item name="keyboardViewStyle">@android:style/Widget.Quantum.KeyboardView</item>
- <item name="quickContactBadgeStyleWindowSmall">@android:style/Widget.Quantum.QuickContactBadge.WindowSmall</item>
- <item name="quickContactBadgeStyleWindowMedium">@android:style/Widget.Quantum.QuickContactBadge.WindowMedium</item>
- <item name="quickContactBadgeStyleWindowLarge">@android:style/Widget.Quantum.QuickContactBadge.WindowLarge</item>
- <item name="quickContactBadgeStyleSmallWindowSmall">@android:style/Widget.Quantum.QuickContactBadgeSmall.WindowSmall</item>
- <item name="quickContactBadgeStyleSmallWindowMedium">@android:style/Widget.Quantum.QuickContactBadgeSmall.WindowMedium</item>
- <item name="quickContactBadgeStyleSmallWindowLarge">@android:style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
- <item name="listPopupWindowStyle">@android:style/Widget.Quantum.Light.ListPopupWindow</item>
- <item name="popupMenuStyle">@android:style/Widget.Quantum.Light.PopupMenu</item>
- <item name="stackViewStyle">@android:style/Widget.Quantum.StackView</item>
- <item name="activityChooserViewStyle">@android:style/Widget.Quantum.Light.ActivityChooserView</item>
- <item name="fragmentBreadCrumbsStyle">@android:style/Widget.Quantum.Light.FragmentBreadCrumbs</item>
+ <item name="absListViewStyle">@style/Widget.Quantum.Light.AbsListView</item>
+ <item name="autoCompleteTextViewStyle">@style/Widget.Quantum.Light.AutoCompleteTextView</item>
+ <item name="checkboxStyle">@style/Widget.Quantum.Light.CompoundButton.CheckBox</item>
+ <item name="checkedTextViewStyle">@style/Widget.Quantum.Light.CheckedTextView</item>
+ <item name="dropDownListViewStyle">@style/Widget.Quantum.ListView.DropDown</item>
+ <item name="editTextStyle">@style/Widget.Quantum.Light.EditText</item>
+ <item name="expandableListViewStyle">@style/Widget.Quantum.Light.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@style/Widget.Quantum.Light.ExpandableListView.White</item>
+ <item name="fastScrollStyle">@style/Widget.Quantum.Light.FastScroll</item>
+ <item name="galleryStyle">@style/Widget.Quantum.Light.Gallery</item>
+ <item name="gestureOverlayViewStyle">@style/Widget.Quantum.Light.GestureOverlayView</item>
+ <item name="gridViewStyle">@style/Widget.Quantum.Light.GridView</item>
+ <item name="imageButtonStyle">@style/Widget.Quantum.Light.ImageButton</item>
+ <item name="imageWellStyle">@style/Widget.Quantum.Light.ImageWell</item>
+ <item name="listViewStyle">@style/Widget.Quantum.Light.ListView</item>
+ <item name="listViewWhiteStyle">@style/Widget.Quantum.Light.ListView.White</item>
+ <item name="popupWindowStyle">@style/Widget.Quantum.Light.PopupWindow</item>
+ <item name="progressBarStyle">@style/Widget.Quantum.Light.ProgressBar</item>
+ <item name="progressBarStyleHorizontal">@style/Widget.Quantum.Light.ProgressBar.Horizontal</item>
+ <item name="progressBarStyleSmall">@style/Widget.Quantum.Light.ProgressBar.Small</item>
+ <item name="progressBarStyleSmallTitle">@style/Widget.Quantum.Light.ProgressBar.Small.Title</item>
+ <item name="progressBarStyleLarge">@style/Widget.Quantum.Light.ProgressBar.Large</item>
+ <item name="progressBarStyleInverse">@style/Widget.Quantum.Light.ProgressBar.Inverse</item>
+ <item name="progressBarStyleSmallInverse">@style/Widget.Quantum.Light.ProgressBar.Small.Inverse</item>
+ <item name="progressBarStyleLargeInverse">@style/Widget.Quantum.Light.ProgressBar.Large.Inverse</item>
+ <item name="seekBarStyle">@style/Widget.Quantum.Light.SeekBar</item>
+ <item name="ratingBarStyle">@style/Widget.Quantum.Light.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@style/Widget.Quantum.Light.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@style/Widget.Quantum.Light.RatingBar.Small</item>
+ <item name="radioButtonStyle">@style/Widget.Quantum.Light.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@style/Widget.Quantum.Light.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@style/Widget.Quantum.Light.HorizontalScrollView</item>
+ <item name="spinnerStyle">?attr/dropDownSpinnerStyle</item>
+ <item name="dropDownSpinnerStyle">@style/Widget.Quantum.Light.Spinner.DropDown</item>
+ <item name="starStyle">@style/Widget.Quantum.Light.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@style/Widget.Quantum.Light.TabWidget</item>
+ <item name="textViewStyle">@style/Widget.Quantum.Light.TextView</item>
+ <item name="errorMessageBackground">@drawable/popup_inline_error_holo_light</item>
+ <item name="errorMessageAboveBackground">@drawable/popup_inline_error_above_holo_light</item>
+ <item name="webTextViewStyle">@style/Widget.Quantum.Light.WebTextView</item>
+ <item name="webViewStyle">@style/Widget.Quantum.Light.WebView</item>
+ <item name="dropDownItemStyle">@style/Widget.Quantum.Light.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@style/Widget.Quantum.Light.DropDownItem.Spinner</item>
+ <item name="spinnerItemStyle">@style/Widget.Quantum.TextView.SpinnerItem</item>
+ <item name="dropDownHintAppearance">@style/TextAppearance.Quantum.Widget.DropDownHint</item>
+ <item name="keyboardViewStyle">@style/Widget.Quantum.KeyboardView</item>
+ <item name="quickContactBadgeStyleWindowSmall">@style/Widget.Quantum.QuickContactBadge.WindowSmall</item>
+ <item name="quickContactBadgeStyleWindowMedium">@style/Widget.Quantum.QuickContactBadge.WindowMedium</item>
+ <item name="quickContactBadgeStyleWindowLarge">@style/Widget.Quantum.QuickContactBadge.WindowLarge</item>
+ <item name="quickContactBadgeStyleSmallWindowSmall">@style/Widget.Quantum.QuickContactBadgeSmall.WindowSmall</item>
+ <item name="quickContactBadgeStyleSmallWindowMedium">@style/Widget.Quantum.QuickContactBadgeSmall.WindowMedium</item>
+ <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Quantum.QuickContactBadgeSmall.WindowLarge</item>
+ <item name="listPopupWindowStyle">@style/Widget.Quantum.Light.ListPopupWindow</item>
+ <item name="popupMenuStyle">@style/Widget.Quantum.Light.PopupMenu</item>
+ <item name="stackViewStyle">@style/Widget.Quantum.StackView</item>
+ <item name="activityChooserViewStyle">@style/Widget.Quantum.Light.ActivityChooserView</item>
+ <item name="fragmentBreadCrumbsStyle">@style/Widget.Quantum.Light.FragmentBreadCrumbs</item>
<!-- Preference styles -->
- <item name="preferenceScreenStyle">@android:style/Preference.Quantum.PreferenceScreen</item>
+ <item name="preferenceScreenStyle">@style/Preference.Quantum.PreferenceScreen</item>
<item name="preferenceFragmentStyle">@style/PreferenceFragment.Quantum</item>
- <item name="preferenceCategoryStyle">@android:style/Preference.Quantum.Category</item>
- <item name="preferenceStyle">@android:style/Preference.Quantum</item>
- <item name="preferenceInformationStyle">@android:style/Preference.Quantum.Information</item>
- <item name="checkBoxPreferenceStyle">@android:style/Preference.Quantum.CheckBoxPreference</item>
- <item name="switchPreferenceStyle">@android:style/Preference.Quantum.SwitchPreference</item>
- <item name="yesNoPreferenceStyle">@android:style/Preference.Quantum.DialogPreference.YesNoPreference</item>
- <item name="dialogPreferenceStyle">@android:style/Preference.Quantum.DialogPreference</item>
- <item name="editTextPreferenceStyle">@android:style/Preference.Quantum.DialogPreference.EditTextPreference</item>
- <item name="ringtonePreferenceStyle">@android:style/Preference.Quantum.RingtonePreference</item>
- <item name="preferenceLayoutChild">@android:layout/preference_child_holo</item>
- <item name="detailsElementBackground">@android:drawable/panel_bg_holo_light</item>
+ <item name="preferenceCategoryStyle">@style/Preference.Quantum.Category</item>
+ <item name="preferenceStyle">@style/Preference.Quantum</item>
+ <item name="preferenceInformationStyle">@style/Preference.Quantum.Information</item>
+ <item name="checkBoxPreferenceStyle">@style/Preference.Quantum.CheckBoxPreference</item>
+ <item name="switchPreferenceStyle">@style/Preference.Quantum.SwitchPreference</item>
+ <item name="yesNoPreferenceStyle">@style/Preference.Quantum.DialogPreference.YesNoPreference</item>
+ <item name="dialogPreferenceStyle">@style/Preference.Quantum.DialogPreference</item>
+ <item name="editTextPreferenceStyle">@style/Preference.Quantum.DialogPreference.EditTextPreference</item>
+ <item name="ringtonePreferenceStyle">@style/Preference.Quantum.RingtonePreference</item>
+ <item name="preferenceLayoutChild">@layout/preference_child_holo</item>
+ <item name="detailsElementBackground">@drawable/panel_bg_holo_light</item>
<!-- PreferenceFrameLayout attributes -->
- <item name="preferenceFrameLayoutStyle">@android:style/Widget.Quantum.PreferenceFrameLayout</item>
+ <item name="preferenceFrameLayoutStyle">@style/Widget.Quantum.PreferenceFrameLayout</item>
<!-- Search widget styles -->
- <item name="searchWidgetCorpusItemBackground">@android:color/search_widget_corpus_item_background</item>
+ <item name="searchWidgetCorpusItemBackground">@color/search_widget_corpus_item_background</item>
<!-- Action bar styles -->
- <item name="actionDropDownStyle">@android:style/Widget.Quantum.Light.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@android:style/Widget.Quantum.Light.ActionButton</item>
- <item name="actionOverflowButtonStyle">@android:style/Widget.Quantum.Light.ActionButton.Overflow</item>
- <item name="actionModeBackground">@android:drawable/cab_background_top_holo_light</item>
- <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_light</item>
- <item name="actionModeCloseDrawable">@android:drawable/ic_cab_done_holo_light</item>
+ <item name="actionDropDownStyle">@style/Widget.Quantum.Light.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@style/Widget.Quantum.Light.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.Quantum.Light.ActionButton.Overflow</item>
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
+ <item name="actionModeCloseDrawable">@drawable/ic_cab_done_holo_light</item>
<item name="actionBarTabStyle">@style/Widget.Quantum.Light.ActionBar.TabView</item>
<item name="actionBarTabBarStyle">@style/Widget.Quantum.Light.ActionBar.TabBar</item>
<item name="actionBarTabTextStyle">@style/Widget.Quantum.Light.ActionBar.TabText</item>
<item name="actionModeStyle">@style/Widget.Quantum.Light.ActionMode</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Quantum.Light.ActionButton.CloseMode</item>
- <item name="android:actionBarStyle">@android:style/Widget.Quantum.Light.ActionBar.Solid</item>
+ <item name="actionBarStyle">@style/Widget.Quantum.Light.ActionBar.Solid</item>
<item name="actionBarSize">@dimen/action_bar_default_height</item>
- <item name="actionModePopupWindowStyle">@android:style/Widget.Quantum.Light.PopupWindow.ActionMode</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.Quantum.Light.PopupWindow.ActionMode</item>
<item name="actionBarWidgetTheme">@null</item>
- <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_light</item>
- <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_light</item>
- <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_light</item>
- <item name="actionModeSelectAllDrawable">@android:drawable/ic_menu_selectall_holo_light</item>
- <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_light</item>
- <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_light</item>
- <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_light</item>
+ <item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_light</item>
+ <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_light</item>
+ <item name="actionModePasteDrawable">@drawable/ic_menu_paste_holo_light</item>
+ <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_holo_light</item>
+ <item name="actionModeShareDrawable">@drawable/ic_menu_share_holo_light</item>
+ <item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_light</item>
+ <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_light</item>
- <item name="dividerVertical">?android:attr/listDivider</item>
- <item name="dividerHorizontal">?android:attr/listDivider</item>
- <item name="buttonBarStyle">@android:style/Quantum.Light.ButtonBar</item>
- <item name="buttonBarButtonStyle">?android:attr/borderlessButtonStyle</item>
- <item name="segmentedButtonStyle">@android:style/Quantum.Light.SegmentedButton</item>
+ <item name="dividerVertical">?attr/listDivider</item>
+ <item name="dividerHorizontal">?attr/listDivider</item>
+ <item name="buttonBarStyle">@style/Quantum.Light.ButtonBar</item>
+ <item name="buttonBarButtonStyle">?attr/borderlessButtonStyle</item>
+ <item name="segmentedButtonStyle">@style/Quantum.Light.SegmentedButton</item>
<!-- SearchView attributes -->
- <item name="searchDropdownBackground">@android:drawable/search_dropdown_light</item>
+ <item name="searchDropdownBackground">@drawable/search_dropdown_light</item>
<item name="searchDialogTheme">@style/Theme.Quantum.Light.SearchBar</item>
@@ -669,7 +671,7 @@
<item name="timePickerStyle">@style/Widget.Quantum.Light.TimePicker</item>
<!-- TimePicker Header background color -->
- <item name="timePickerHeaderBackgroundColor">@android:color/timepicker_default_background_holo_light</item>
+ <item name="timePickerHeaderBackgroundColor">@color/timepicker_default_background_quantum_light</item>
<!-- TimePicker Header time label text appearance -->
<item name="timePickerHeaderTimeLabelTextAppearance">@style/TextAppearance.Quantum.Light.TimePicker.TimeLabel</item>
@@ -678,15 +680,15 @@
<item name="timePickerHeaderAmPmLabelTextAppearance">@style/TextAppearance.Quantum.Light.TimePicker.AmPmLabel</item>
<!-- TimePicker dialog theme -->
- <item name="timePickerDialogTheme">@android:style/Theme.Quantum.Light.Dialog.TimePicker</item>
+ <item name="timePickerDialogTheme">@style/Theme.Quantum.Light.Dialog.TimePicker</item>
<!-- DatePicker style -->
<item name="datePickerStyle">@style/Widget.Quantum.Light.DatePicker</item>
- <item name="fastScrollThumbDrawable">@android:drawable/fastscroll_thumb_holo</item>
- <item name="fastScrollPreviewBackgroundLeft">@android:drawable/fastscroll_label_left_holo_light</item>
- <item name="fastScrollPreviewBackgroundRight">@android:drawable/fastscroll_label_right_holo_light</item>
- <item name="fastScrollTrackDrawable">@android:drawable/fastscroll_track_holo_light</item>
+ <item name="fastScrollThumbDrawable">@drawable/fastscroll_thumb_holo</item>
+ <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item>
+ <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item>
+ <item name="fastScrollTrackDrawable">@drawable/fastscroll_track_holo_light</item>
<item name="fastScrollOverlayPosition">atThumb</item>
</style>
@@ -695,48 +697,47 @@
with an inverse color profile. The dark action bar sharply stands out against
the light content. -->
<style name="Theme.Quantum.Light.DarkActionBar">
- <item name="android:windowContentOverlay">@android:drawable/ab_solid_shadow_holo</item>
- <item name="android:actionBarStyle">@android:style/Widget.Quantum.Light.ActionBar.Solid.Inverse</item>
- <item name="actionBarWidgetTheme">@android:style/Theme.Quantum</item>
+ <item name="windowContentOverlay">@drawable/ab_solid_shadow_holo</item>
+ <item name="actionBarStyle">@style/Widget.Quantum.Light.ActionBar.Solid.Inverse</item>
+ <item name="actionBarWidgetTheme">@style/Theme.Quantum</item>
- <item name="actionDropDownStyle">@android:style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
- <item name="actionButtonStyle">@android:style/Widget.Quantum.ActionButton</item>
- <item name="actionOverflowButtonStyle">@android:style/Widget.Quantum.ActionButton.Overflow</item>
- <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
- <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_dark</item>
- <item name="actionModeCloseDrawable">@android:drawable/ic_cab_done_holo_dark</item>
- <item name="homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
+ <item name="actionDropDownStyle">@style/Widget.Quantum.Spinner.DropDown.ActionBar</item>
+ <item name="actionButtonStyle">@style/Widget.Quantum.ActionButton</item>
+ <item name="actionOverflowButtonStyle">@style/Widget.Quantum.ActionButton.Overflow</item>
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_dark</item>
+ <item name="actionModeCloseDrawable">@drawable/ic_cab_done_holo_dark</item>
+ <item name="homeAsUpIndicator">@drawable/ic_ab_back_holo_dark</item>
<item name="actionBarTabStyle">@style/Widget.Quantum.Light.ActionBar.TabView.Inverse</item>
<item name="actionBarTabBarStyle">@style/Widget.Quantum.Light.ActionBar.TabBar.Inverse</item>
<item name="actionBarTabTextStyle">@style/Widget.Quantum.Light.ActionBar.TabText.Inverse</item>
- <item name="actionBarDivider">@android:drawable/list_divider_holo_dark</item>
- <item name="actionBarItemBackground">@android:drawable/item_background_holo_dark</item>
- <item name="actionMenuTextColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="actionBarDivider">@drawable/list_divider_holo_dark</item>
+ <item name="actionMenuTextColor">?attr/textColorPrimaryInverse</item>
<item name="actionModeStyle">@style/Widget.Quantum.Light.ActionMode.Inverse</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Quantum.ActionButton.CloseMode</item>
- <item name="actionModePopupWindowStyle">@android:style/Widget.Quantum.PopupWindow.ActionMode</item>
+ <item name="actionModePopupWindowStyle">@style/Widget.Quantum.PopupWindow.ActionMode</item>
- <item name="actionModeCutDrawable">@android:drawable/ic_menu_cut_holo_dark</item>
- <item name="actionModeCopyDrawable">@android:drawable/ic_menu_copy_holo_dark</item>
- <item name="actionModePasteDrawable">@android:drawable/ic_menu_paste_holo_dark</item>
- <item name="actionModeSelectAllDrawable">@android:drawable/ic_menu_selectall_holo_dark</item>
- <item name="actionModeShareDrawable">@android:drawable/ic_menu_share_holo_dark</item>
- <item name="actionModeFindDrawable">@android:drawable/ic_menu_find_holo_dark</item>
- <item name="actionModeWebSearchDrawable">@android:drawable/ic_menu_search_holo_dark</item>
+ <item name="actionModeCutDrawable">@drawable/ic_menu_cut_holo_dark</item>
+ <item name="actionModeCopyDrawable">@drawable/ic_menu_copy_holo_dark</item>
+ <item name="actionModePasteDrawable">@drawable/ic_menu_paste_holo_dark</item>
+ <item name="actionModeSelectAllDrawable">@drawable/ic_menu_selectall_holo_dark</item>
+ <item name="actionModeShareDrawable">@drawable/ic_menu_share_holo_dark</item>
+ <item name="actionModeFindDrawable">@drawable/ic_menu_find_holo_dark</item>
+ <item name="actionModeWebSearchDrawable">@drawable/ic_menu_search_holo_dark</item>
</style>
<!-- Variant of the quantum (dark) theme with no action bar. -->
<style name="Theme.Quantum.NoActionBar">
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
</style>
<!-- Variant of the quantum (dark) theme that has no title bar and fills
the entire screen. This theme
sets {@link android.R.attr#windowFullscreen} to true. -->
<style name="Theme.Quantum.NoActionBar.Fullscreen">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowContentOverlay">@null</item>
+ <item name="windowFullscreen">true</item>
+ <item name="windowContentOverlay">@null</item>
</style>
<!-- Variant of the quantum (dark) theme that has no title bar and fills
@@ -744,32 +745,32 @@
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
<style name="Theme.Quantum.NoActionBar.Overscan">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowOverscan">true</item>
- <item name="android:windowContentOverlay">@null</item>
+ <item name="windowFullscreen">true</item>
+ <item name="windowOverscan">true</item>
+ <item name="windowContentOverlay">@null</item>
</style>
<!-- Variant of the quantum (dark) theme that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
{@link android.R.attr#windowTranslucentNavigation} to true. -->
<style name="Theme.Quantum.NoActionBar.TranslucentDecor">
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:windowTranslucentNavigation">true</item>
- <item name="android:windowContentOverlay">@null</item>
+ <item name="windowTranslucentStatus">true</item>
+ <item name="windowTranslucentNavigation">true</item>
+ <item name="windowContentOverlay">@null</item>
</style>
<!-- Variant of the quantum (light) theme with no action bar. -->
<style name="Theme.Quantum.Light.NoActionBar">
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
</style>
<!-- Variant of the quantum (light) theme that has no title bar and fills
the entire screen. This theme
sets {@link android.R.attr#windowFullscreen} to true. -->
<style name="Theme.Quantum.Light.NoActionBar.Fullscreen">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowContentOverlay">@null</item>
+ <item name="windowFullscreen">true</item>
+ <item name="windowContentOverlay">@null</item>
</style>
<!-- Variant of the quantum (light) theme that has no title bar and fills
@@ -777,18 +778,18 @@
sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
to true. -->
<style name="Theme.Quantum.Light.NoActionBar.Overscan">
- <item name="android:windowFullscreen">true</item>
- <item name="android:windowOverscan">true</item>
- <item name="android:windowContentOverlay">@null</item>
+ <item name="windowFullscreen">true</item>
+ <item name="windowOverscan">true</item>
+ <item name="windowContentOverlay">@null</item>
</style>
<!-- Variant of the quantum (light) theme that has no title bar and translucent
system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
{@link android.R.attr#windowTranslucentNavigation} to true. -->
<style name="Theme.Quantum.Light.NoActionBar.TranslucentDecor">
- <item name="android:windowTranslucentStatus">true</item>
- <item name="android:windowTranslucentNavigation">true</item>
- <item name="android:windowContentOverlay">@null</item>
+ <item name="windowTranslucentStatus">true</item>
+ <item name="windowTranslucentNavigation">true</item>
+ <item name="windowContentOverlay">@null</item>
</style>
<!-- Default quantum dark theme for panel windows. This removes all extraneous
@@ -796,15 +797,15 @@
to place your content. It makes the window floating, with a transparent
background, and turns off dimming behind the window. -->
<style name="Theme.Quantum.Panel">
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:windowFrame">@null</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowAnimationStyle">@null</item>
- <item name="android:windowIsFloating">true</item>
- <item name="android:backgroundDimEnabled">false</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="windowIsFloating">true</item>
+ <item name="backgroundDimEnabled">false</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
</style>
<!-- Default quantum light theme for panel windows. This removes all extraneous
@@ -812,15 +813,15 @@
to place your content. It makes the window floating, with a transparent
background, and turns off dimming behind the window. -->
<style name="Theme.Quantum.Light.Panel">
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:windowFrame">@null</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowAnimationStyle">@null</item>
- <item name="android:windowIsFloating">true</item>
- <item name="android:backgroundDimEnabled">false</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="windowIsFloating">true</item>
+ <item name="backgroundDimEnabled">false</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
</style>
<!-- Default theme for quantum style input methods, which is used by the
@@ -828,22 +829,22 @@
this inherits from Theme.Panel, but sets up IME appropriate animations
and a few custom attributes. -->
<style name="Theme.Quantum.InputMethod" parent="Theme.Quantum.Light.Panel">
- <item name="android:windowAnimationStyle">@android:style/Animation.InputMethod</item>
- <item name="android:imeFullscreenBackground">@android:drawable/screen_background_selector_light</item>
- <item name="android:imeExtractEnterAnimation">@android:anim/input_method_extract_enter</item>
- <item name="android:imeExtractExitAnimation">@android:anim/input_method_extract_exit</item>
+ <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
+ <item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item>
+ <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
+ <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
</style>
<!-- Theme for the search input bar. -->
<style name="Theme.Quantum.SearchBar" parent="Theme.Quantum.Panel">
- <item name="actionModeBackground">@android:drawable/cab_background_top_holo_dark</item>
- <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_light</item>
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_dark</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
</style>
<style name="Theme.Quantum.Light.SearchBar" parent="Theme.Quantum.Light.Panel">
- <item name="actionModeBackground">@android:drawable/cab_background_top_holo_light</item>
- <item name="actionModeSplitBackground">@android:drawable/cab_background_bottom_holo_light</item>
+ <item name="actionModeBackground">@drawable/cab_background_top_holo_light</item>
+ <item name="actionModeSplitBackground">@drawable/cab_background_bottom_holo_light</item>
</style>
<!-- Menu Themes -->
@@ -851,18 +852,18 @@
<style name="Theme.Quantum.CompactMenu">
<!-- Menu/item attributes -->
- <item name="android:itemTextAppearance">?android:attr/textAppearanceMedium</item>
- <item name="android:listViewStyle">@android:style/Widget.Quantum.ListView</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.DropDownUp</item>
- <item name="android:background">@null</item>
+ <item name="itemTextAppearance">?attr/textAppearanceMedium</item>
+ <item name="listViewStyle">@style/Widget.Quantum.ListView</item>
+ <item name="windowAnimationStyle">@style/Animation.DropDownUp</item>
+ <item name="background">@null</item>
</style>
<style name="Theme.Quantum.Light.CompactMenu">
<!-- Menu/item attributes -->
- <item name="android:itemTextAppearance">?android:attr/textAppearanceMedium</item>
- <item name="android:listViewStyle">@android:style/Widget.Quantum.Light.ListView</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.DropDownUp</item>
- <item name="android:background">@null</item>
+ <item name="itemTextAppearance">?attr/textAppearanceMedium</item>
+ <item name="listViewStyle">@style/Widget.Quantum.Light.ListView</item>
+ <item name="windowAnimationStyle">@style/Animation.DropDownUp</item>
+ <item name="background">@null</item>
</style>
<!-- Dialog themes for Quantum -->
@@ -874,24 +875,24 @@
contents. You can set this theme on an activity if you would like to
make an activity that looks like a Dialog. -->
<style name="Theme.Quantum.Dialog">
- <item name="android:windowFrame">@null</item>
- <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.Quantum</item>
- <item name="android:windowBackground">@android:drawable/dialog_full_holo_dark</item>
- <item name="android:windowIsFloating">true</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.Quantum.Dialog</item>
- <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
- <item name="android:windowActionBar">false</item>
- <item name="android:windowActionModeOverlay">true</item>
- <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
+ <item name="windowBackground">@drawable/dialog_full_holo_dark</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@style/Animation.Quantum.Dialog</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="colorBackgroundCacheHint">@null</item>
- <item name="android:buttonBarStyle">@android:style/Quantum.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@android:style/Widget.Quantum.Button.Borderless.Small</item>
+ <item name="buttonBarStyle">@style/Quantum.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.Quantum.Button.Borderless.Small</item>
- <item name="textAppearance">@android:style/TextAppearance.Quantum</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.Quantum.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Inverse</item>
<item name="listPreferredItemPaddingLeft">16dip</item>
<item name="listPreferredItemPaddingRight">16dip</item>
@@ -904,51 +905,51 @@
<!-- Variant of Theme.Quantum.Dialog that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Quantum.Dialog.MinWidth">
- <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
- <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
<!-- Variant of Theme.Quantum.Dialog that does not include a title bar. -->
<style name="Theme.Quantum.Dialog.NoActionBar">
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
</style>
<!-- Variant of Theme.Quantum.Dialog.NoActionBar that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Quantum.Dialog.NoActionBar.MinWidth">
- <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
- <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
<!-- Variant of Theme.Quantum.Dialog that has a fixed size. -->
<style name="Theme.Quantum.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
</style>
<!-- Variant of Theme.Quantum.Dialog.NoActionBar that has a fixed size. -->
<style name="Theme.Quantum.Dialog.NoActionBar.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
</style>
<!-- Variant of Theme.Quantum.Dialog that does not include a frame (or background).
The view hierarchy of the dialog is responsible for drawing all of
its pixels. -->
<style name="Theme.Quantum.Dialog.NoFrame">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="android:windowFrame">@null</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowFrame">@null</item>
<item name="windowContentOverlay">@null</item>
- <item name="android:windowAnimationStyle">@null</item>
- <item name="android:backgroundDimEnabled">false</item>
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowNoTitle">true</item>
- <item name="android:windowCloseOnTouchOutside">false</item>
+ <item name="windowAnimationStyle">@null</item>
+ <item name="backgroundDimEnabled">false</item>
+ <item name="windowIsTranslucent">true</item>
+ <item name="windowNoTitle">true</item>
+ <item name="windowCloseOnTouchOutside">false</item>
</style>
<!-- Quantum theme for alert dialog windows, which is used by the
@@ -957,35 +958,35 @@
For applications targeting Honeycomb or newer, this is the default
AlertDialog theme. -->
<style name="Theme.Quantum.Dialog.Alert">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.Quantum</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
<item name="windowContentOverlay">@null</item>
- <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
- <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
<!-- Quantum theme for the TimePicker dialog windows, which is used by the
{@link android.app.TimePickerDialog} class. -->
<style name="Theme.Quantum.Dialog.TimePicker">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.Quantum</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum</item>
<item name="windowContentOverlay">@null</item>
</style>
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Quantum.DialogWhenLarge" parent="@android:style/Theme.Quantum">
+ <style name="Theme.Quantum.DialogWhenLarge" parent="@style/Theme.Quantum">
</style>
<!-- Theme for a window without a title bar that will be displayed either
full-screen on smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Quantum.DialogWhenLarge.NoActionBar" parent="@android:style/Theme.Quantum.NoActionBar">
+ <style name="Theme.Quantum.DialogWhenLarge.NoActionBar" parent="@style/Theme.Quantum.NoActionBar">
</style>
<!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Quantum.Dialog.Presentation" parent="@android:style/Theme.Quantum.NoActionBar.Fullscreen">
+ <style name="Theme.Quantum.Dialog.Presentation" parent="@style/Theme.Quantum.NoActionBar.Fullscreen">
</style>
<!-- Light quantum dialog themes -->
@@ -996,24 +997,24 @@
contents. You can set this theme on an activity if you would like to
make an activity that looks like a Dialog. -->
<style name="Theme.Quantum.Light.Dialog">
- <item name="android:windowFrame">@null</item>
- <item name="android:windowTitleStyle">@android:style/DialogWindowTitle.Quantum.Light</item>
- <item name="android:windowBackground">@android:drawable/dialog_full_holo_light</item>
- <item name="android:windowIsFloating">true</item>
- <item name="android:windowContentOverlay">@null</item>
- <item name="android:windowAnimationStyle">@android:style/Animation.Quantum.Dialog</item>
- <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
- <item name="android:windowActionBar">false</item>
- <item name="android:windowActionModeOverlay">true</item>
- <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+ <item name="windowFrame">@null</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
+ <item name="windowBackground">@drawable/dialog_full_holo_light</item>
+ <item name="windowIsFloating">true</item>
+ <item name="windowContentOverlay">@null</item>
+ <item name="windowAnimationStyle">@style/Animation.Quantum.Dialog</item>
+ <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowActionModeOverlay">true</item>
+ <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="colorBackgroundCacheHint">@null</item>
- <item name="android:buttonBarStyle">@android:style/Quantum.Light.ButtonBar.AlertDialog</item>
- <item name="borderlessButtonStyle">@android:style/Widget.Quantum.Light.Button.Borderless.Small</item>
+ <item name="buttonBarStyle">@style/Quantum.Light.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.Quantum.Light.Button.Borderless.Small</item>
- <item name="textAppearance">@android:style/TextAppearance.Quantum.Light</item>
- <item name="textAppearanceInverse">@android:style/TextAppearance.Quantum.Light.Inverse</item>
+ <item name="textAppearance">@style/TextAppearance.Quantum.Light</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.Quantum.Light.Inverse</item>
<item name="listPreferredItemPaddingLeft">16dip</item>
<item name="listPreferredItemPaddingRight">16dip</item>
@@ -1026,50 +1027,50 @@
<!-- Variant of Theme.Quantum.Light.Dialog that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Quantum.Light.Dialog.MinWidth">
- <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
- <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
<!-- Variant of Theme.Quantum.Light.Dialog that does not include a title bar. -->
<style name="Theme.Quantum.Light.Dialog.NoActionBar">
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
</style>
<!-- Variant of Theme.Quantum.Light.Dialog.NoActionBar that has a nice minimum width for
a regular dialog. -->
<style name="Theme.Quantum.Light.Dialog.NoActionBar.MinWidth">
- <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
- <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
<!-- Variant of Theme.Quantum.Light.Dialog that has a fixed size. -->
<style name="Theme.Quantum.Light.Dialog.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
</style>
<!-- Variant of Theme.Quantum.Light.Dialog.NoActionBar that has a fixed size. -->
<style name="Theme.Quantum.Light.Dialog.NoActionBar.FixedSize">
- <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
- <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
- <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
- <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+ <item name="windowFixedWidthMajor">@dimen/dialog_fixed_width_major</item>
+ <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
+ <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
+ <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
</style>
<!-- Theme for a window that will be displayed either full-screen on
smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
- <style name="Theme.Quantum.Light.DialogWhenLarge" parent="@android:style/Theme.Quantum.Light">
+ <style name="Theme.Quantum.Light.DialogWhenLarge" parent="@style/Theme.Quantum.Light">
</style>
<!-- Theme for a window without an action bar that will be displayed either full-screen
on smaller screens (small, normal) or as a dialog on larger screens
(large, xlarge). -->
<style name="Theme.Quantum.Light.DialogWhenLarge.NoActionBar"
- parent="@android:style/Theme.Quantum.Light.NoActionBar">
+ parent="@style/Theme.Quantum.Light.NoActionBar">
</style>
<!-- Quantum light theme for alert dialog windows, which is used by the
@@ -1078,37 +1079,37 @@
For applications targeting Honeycomb or newer, this is the default
AlertDialog theme. -->
<style name="Theme.Quantum.Light.Dialog.Alert">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.Quantum.Light</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
<item name="windowContentOverlay">@null</item>
- <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
- <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+ <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+ <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
</style>
<!-- Quantum Light theme for the TimePicker dialog windows, which is used by the
{@link android.app.TimePickerDialog} class. -->
<style name="Theme.Quantum.Light.Dialog.TimePicker">
- <item name="windowBackground">@android:color/transparent</item>
- <item name="windowTitleStyle">@android:style/DialogWindowTitle.Quantum.Light</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.Quantum.Light</item>
<item name="windowContentOverlay">@null</item>
</style>
<!-- Theme for a presentation window on a secondary display. -->
- <style name="Theme.Quantum.Light.Dialog.Presentation" parent="@android:style/Theme.Quantum.Light.NoActionBar.Fullscreen" >
+ <style name="Theme.Quantum.Light.Dialog.Presentation" parent="@style/Theme.Quantum.Light.NoActionBar.Fullscreen" >
</style>
<!-- Default quantum (dark) for windows that want to have the user's selected
wallpaper appear behind them. -->
<style name="Theme.Quantum.Wallpaper">
- <item name="android:windowBackground">@android:color/transparent</item>
- <item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:windowShowWallpaper">true</item>
+ <item name="windowBackground">@color/transparent</item>
+ <item name="colorBackgroundCacheHint">@null</item>
+ <item name="windowShowWallpaper">true</item>
</style>
<!--Default quantum (dark) for windows that want to have the user's selected
wallpaper appear behind them and without an action bar. -->
<style name="Theme.Quantum.Wallpaper.NoTitleBar">
- <item name="android:windowNoTitle">true</item>
+ <item name="windowNoTitle">true</item>
</style>
</resources>
diff --git a/core/tests/coretests/src/android/util/JsonReaderTest.java b/core/tests/coretests/src/android/util/JsonReaderTest.java
deleted file mode 100644
index 42b7640..0000000
--- a/core/tests/coretests/src/android/util/JsonReaderTest.java
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.Arrays;
-import junit.framework.TestCase;
-
-public final class JsonReaderTest extends TestCase {
-
- private static final int READER_BUFFER_SIZE = 1024;
-
- public void testReadArray() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[true, true]"));
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- assertEquals(true, reader.nextBoolean());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testReadEmptyArray() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[]"));
- reader.beginArray();
- assertFalse(reader.hasNext());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testReadObject() throws IOException {
- JsonReader reader = new JsonReader(new StringReader(
- "{\"a\": \"android\", \"b\": \"banana\"}"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- assertEquals("android", reader.nextString());
- assertEquals("b", reader.nextName());
- assertEquals("banana", reader.nextString());
- reader.endObject();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testReadEmptyObject() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{}"));
- reader.beginObject();
- assertFalse(reader.hasNext());
- reader.endObject();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testSkipObject() throws IOException {
- JsonReader reader = new JsonReader(new StringReader(
- "{\"a\": { \"c\": [], \"d\": [true, true, {}] }, \"b\": \"banana\"}"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- reader.skipValue();
- assertEquals("b", reader.nextName());
- reader.skipValue();
- reader.endObject();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testHelloWorld() throws IOException {
- String json = "{\n" +
- " \"hello\": true,\n" +
- " \"foo\": [\"world\"]\n" +
- "}";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginObject();
- assertEquals("hello", reader.nextName());
- assertEquals(true, reader.nextBoolean());
- assertEquals("foo", reader.nextName());
- reader.beginArray();
- assertEquals("world", reader.nextString());
- reader.endArray();
- reader.endObject();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testNulls() {
- try {
- new JsonReader(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- public void testEmptyString() throws IOException {
- try {
- new JsonReader(new StringReader("")).beginArray();
- } catch (IOException expected) {
- }
- try {
- new JsonReader(new StringReader("")).beginObject();
- } catch (IOException expected) {
- }
- }
-
- public void testNoTopLevelObject() throws IOException {
- try {
- new JsonReader(new StringReader("true")).nextBoolean();
- } catch (IOException expected) {
- }
- }
-
- public void testCharacterUnescaping() throws IOException {
- String json = "[\"a\","
- + "\"a\\\"\","
- + "\"\\\"\","
- + "\":\","
- + "\",\","
- + "\"\\b\","
- + "\"\\f\","
- + "\"\\n\","
- + "\"\\r\","
- + "\"\\t\","
- + "\" \","
- + "\"\\\\\","
- + "\"{\","
- + "\"}\","
- + "\"[\","
- + "\"]\","
- + "\"\\u0000\","
- + "\"\\u0019\","
- + "\"\\u20AC\""
- + "]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- assertEquals("a", reader.nextString());
- assertEquals("a\"", reader.nextString());
- assertEquals("\"", reader.nextString());
- assertEquals(":", reader.nextString());
- assertEquals(",", reader.nextString());
- assertEquals("\b", reader.nextString());
- assertEquals("\f", reader.nextString());
- assertEquals("\n", reader.nextString());
- assertEquals("\r", reader.nextString());
- assertEquals("\t", reader.nextString());
- assertEquals(" ", reader.nextString());
- assertEquals("\\", reader.nextString());
- assertEquals("{", reader.nextString());
- assertEquals("}", reader.nextString());
- assertEquals("[", reader.nextString());
- assertEquals("]", reader.nextString());
- assertEquals("\0", reader.nextString());
- assertEquals("\u0019", reader.nextString());
- assertEquals("\u20AC", reader.nextString());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testIntegersWithFractionalPartSpecified() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[1.0,1.0,1.0]"));
- reader.beginArray();
- assertEquals(1.0, reader.nextDouble());
- assertEquals(1, reader.nextInt());
- assertEquals(1L, reader.nextLong());
- }
-
- public void testDoubles() throws IOException {
- String json = "[-0.0,"
- + "1.0,"
- + "1.7976931348623157E308,"
- + "4.9E-324,"
- + "0.0,"
- + "-0.5,"
- + "2.2250738585072014E-308,"
- + "3.141592653589793,"
- + "2.718281828459045,"
- + "\"1.0\","
- + "\"011.0\","
- + "\"NaN\","
- + "\"Infinity\","
- + "\"-Infinity\""
- + "]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- assertEquals(-0.0, reader.nextDouble());
- assertEquals(1.0, reader.nextDouble());
- assertEquals(1.7976931348623157E308, reader.nextDouble());
- assertEquals(4.9E-324, reader.nextDouble());
- assertEquals(0.0, reader.nextDouble());
- assertEquals(-0.5, reader.nextDouble());
- assertEquals(2.2250738585072014E-308, reader.nextDouble());
- assertEquals(3.141592653589793, reader.nextDouble());
- assertEquals(2.718281828459045, reader.nextDouble());
- assertEquals(1,0, reader.nextDouble());
- assertEquals(11.0, reader.nextDouble());
- assertTrue(Double.isNaN(reader.nextDouble()));
- assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble());
- assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testLenientDoubles() throws IOException {
- String json = "["
- + "011.0,"
- + "NaN,"
- + "NAN,"
- + "Infinity,"
- + "INFINITY,"
- + "-Infinity"
- + "]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(11.0, reader.nextDouble());
- assertTrue(Double.isNaN(reader.nextDouble()));
- try {
- reader.nextDouble();
- fail();
- } catch (NumberFormatException expected) {
- }
- assertEquals("NAN", reader.nextString());
- assertEquals(Double.POSITIVE_INFINITY, reader.nextDouble());
- try {
- reader.nextDouble();
- fail();
- } catch (NumberFormatException expected) {
- }
- assertEquals("INFINITY", reader.nextString());
- assertEquals(Double.NEGATIVE_INFINITY, reader.nextDouble());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testBufferBoundary() throws IOException {
- char[] pad = new char[READER_BUFFER_SIZE - 8];
- Arrays.fill(pad, '5');
- String json = "[\"" + new String(pad) + "\",33333]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- assertEquals(JsonToken.STRING, reader.peek());
- assertEquals(new String(pad), reader.nextString());
- assertEquals(JsonToken.NUMBER, reader.peek());
- assertEquals(33333, reader.nextInt());
- }
-
- public void testTruncatedBufferBoundary() throws IOException {
- char[] pad = new char[READER_BUFFER_SIZE - 8];
- Arrays.fill(pad, '5');
- String json = "[\"" + new String(pad) + "\",33333";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(JsonToken.STRING, reader.peek());
- assertEquals(new String(pad), reader.nextString());
- assertEquals(JsonToken.NUMBER, reader.peek());
- assertEquals(33333, reader.nextInt());
- try {
- reader.endArray();
- fail();
- } catch (IOException e) {
- }
- }
-
- public void testLongestSupportedNumericLiterals() throws IOException {
- testLongNumericLiterals(READER_BUFFER_SIZE - 1, JsonToken.NUMBER);
- }
-
- public void testLongerNumericLiterals() throws IOException {
- testLongNumericLiterals(READER_BUFFER_SIZE, JsonToken.STRING);
- }
-
- private void testLongNumericLiterals(int length, JsonToken expectedToken) throws IOException {
- char[] longNumber = new char[length];
- Arrays.fill(longNumber, '9');
- longNumber[0] = '1';
- longNumber[1] = '.';
-
- String json = "[" + new String(longNumber) + "]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(expectedToken, reader.peek());
- assertEquals(2.0d, reader.nextDouble());
- reader.endArray();
- }
-
- public void testLongs() throws IOException {
- String json = "[0,0,0,"
- + "1,1,1,"
- + "-1,-1,-1,"
- + "-9223372036854775808,"
- + "9223372036854775807,"
- + "5.0,"
- + "1.0e2,"
- + "\"011\","
- + "\"5.0\","
- + "\"1.0e2\""
- + "]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- assertEquals(0L, reader.nextLong());
- assertEquals(0, reader.nextInt());
- assertEquals(0.0, reader.nextDouble());
- assertEquals(1L, reader.nextLong());
- assertEquals(1, reader.nextInt());
- assertEquals(1.0, reader.nextDouble());
- assertEquals(-1L, reader.nextLong());
- assertEquals(-1, reader.nextInt());
- assertEquals(-1.0, reader.nextDouble());
- try {
- reader.nextInt();
- fail();
- } catch (NumberFormatException expected) {
- }
- assertEquals(Long.MIN_VALUE, reader.nextLong());
- try {
- reader.nextInt();
- fail();
- } catch (NumberFormatException expected) {
- }
- assertEquals(Long.MAX_VALUE, reader.nextLong());
- assertEquals(5, reader.nextLong());
- assertEquals(100, reader.nextLong());
- assertEquals(11, reader.nextLong());
- assertEquals(5, reader.nextLong());
- assertEquals(100, reader.nextLong());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- /**
- * This test fails because there's no double for 9223372036854775806, and
- * our long parsing uses Double.parseDouble() for fractional values.
- */
- public void testHighPrecisionLong() throws IOException {
- String json = "[9223372036854775806.000]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- assertEquals(9223372036854775806L, reader.nextLong());
- reader.endArray();
- }
-
- public void testMatchingValidNumbers() throws IOException {
- String json = "[-1,99,-0,0,0e1,0e+1,0e-1,0E1,0E+1,0E-1,0.0,1.0,-1.0,1.0e0,1.0e+1,1.0e-1]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- for (int i = 0; i < 16; i++) {
- assertEquals(JsonToken.NUMBER, reader.peek());
- reader.nextDouble();
- }
- reader.endArray();
- }
-
- public void testRecognizingInvalidNumbers() throws IOException {
- String json = "[-00,00,001,+1,1f,0x,0xf,0x0,0f1,0ee1,1..0,1e0.1,1.-01,1.+1,1.0x,1.0+]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.setLenient(true);
- reader.beginArray();
- for (int i = 0; i < 16; i++) {
- assertEquals(JsonToken.STRING, reader.peek());
- reader.nextString();
- }
- reader.endArray();
- }
-
- public void testNonFiniteDouble() throws IOException {
- String json = "[NaN]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- try {
- reader.nextDouble();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testNumberWithHexPrefix() throws IOException {
- String json = "[0x11]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- try {
- reader.nextLong();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testNumberWithOctalPrefix() throws IOException {
- String json = "[01]";
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- try {
- reader.nextInt();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testBooleans() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[true,false]"));
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- assertEquals(false, reader.nextBoolean());
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testMixedCaseLiterals() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[True,TruE,False,FALSE,NULL,nulL]"));
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- assertEquals(true, reader.nextBoolean());
- assertEquals(false, reader.nextBoolean());
- assertEquals(false, reader.nextBoolean());
- reader.nextNull();
- reader.nextNull();
- reader.endArray();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testMissingValue() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":}"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- try {
- reader.nextString();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testPrematureEndOfInput() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":true,"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- assertEquals(true, reader.nextBoolean());
- try {
- reader.nextName();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testPrematurelyClosed() throws IOException {
- try {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":[]}"));
- reader.beginObject();
- reader.close();
- reader.nextName();
- fail();
- } catch (IllegalStateException expected) {
- }
-
- try {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":[]}"));
- reader.close();
- reader.beginObject();
- fail();
- } catch (IllegalStateException expected) {
- }
-
- try {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":true}"));
- reader.beginObject();
- reader.nextName();
- reader.peek();
- reader.close();
- reader.nextBoolean();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testNextFailuresDoNotAdvance() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":true}"));
- reader.beginObject();
- try {
- reader.nextString();
- fail();
- } catch (IllegalStateException expected) {
- }
- assertEquals("a", reader.nextName());
- try {
- reader.nextName();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.beginArray();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.endArray();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.beginObject();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.endObject();
- fail();
- } catch (IllegalStateException expected) {
- }
- assertEquals(true, reader.nextBoolean());
- try {
- reader.nextString();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.nextName();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.beginArray();
- fail();
- } catch (IllegalStateException expected) {
- }
- try {
- reader.endArray();
- fail();
- } catch (IllegalStateException expected) {
- }
- reader.endObject();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- reader.close();
- }
-
- public void testStringNullIsNotNull() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[\"null\"]"));
- reader.beginArray();
- try {
- reader.nextNull();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testNullLiteralIsNotAString() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[null]"));
- reader.beginArray();
- try {
- reader.nextString();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testStrictNameValueSeparator() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\"=true}"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
-
- reader = new JsonReader(new StringReader("{\"a\"=>true}"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientNameValueSeparator() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\"=true}"));
- reader.setLenient(true);
- reader.beginObject();
- assertEquals("a", reader.nextName());
- assertEquals(true, reader.nextBoolean());
-
- reader = new JsonReader(new StringReader("{\"a\"=>true}"));
- reader.setLenient(true);
- reader.beginObject();
- assertEquals("a", reader.nextName());
- assertEquals(true, reader.nextBoolean());
- }
-
- public void testStrictComments() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[// comment \n true]"));
- reader.beginArray();
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
-
- reader = new JsonReader(new StringReader("[# comment \n true]"));
- reader.beginArray();
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
-
- reader = new JsonReader(new StringReader("[/* comment */ true]"));
- reader.beginArray();
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientComments() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[// comment \n true]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
-
- reader = new JsonReader(new StringReader("[# comment \n true]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
-
- reader = new JsonReader(new StringReader("[/* comment */ true]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- }
-
- public void testStrictUnquotedNames() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{a:true}"));
- reader.beginObject();
- try {
- reader.nextName();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientUnquotedNames() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{a:true}"));
- reader.setLenient(true);
- reader.beginObject();
- assertEquals("a", reader.nextName());
- }
-
- public void testStrictSingleQuotedNames() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{'a':true}"));
- reader.beginObject();
- try {
- reader.nextName();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientSingleQuotedNames() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{'a':true}"));
- reader.setLenient(true);
- reader.beginObject();
- assertEquals("a", reader.nextName());
- }
-
- public void testStrictUnquotedStrings() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[a]"));
- reader.beginArray();
- try {
- reader.nextString();
- fail();
- } catch (MalformedJsonException expected) {
- }
- }
-
- public void testLenientUnquotedStrings() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[a]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals("a", reader.nextString());
- }
-
- public void testStrictSingleQuotedStrings() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("['a']"));
- reader.beginArray();
- try {
- reader.nextString();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientSingleQuotedStrings() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("['a']"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals("a", reader.nextString());
- }
-
- public void testStrictSemicolonDelimitedArray() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[true;true]"));
- reader.beginArray();
- try {
- reader.nextBoolean();
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientSemicolonDelimitedArray() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[true;true]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- assertEquals(true, reader.nextBoolean());
- }
-
- public void testStrictSemicolonDelimitedNameValuePair() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":true;\"b\":true}"));
- reader.beginObject();
- assertEquals("a", reader.nextName());
- try {
- reader.nextBoolean();
- reader.nextName();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientSemicolonDelimitedNameValuePair() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("{\"a\":true;\"b\":true}"));
- reader.setLenient(true);
- reader.beginObject();
- assertEquals("a", reader.nextName());
- assertEquals(true, reader.nextBoolean());
- assertEquals("b", reader.nextName());
- }
-
- public void testStrictUnnecessaryArraySeparators() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[true,,true]"));
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- try {
- reader.nextNull();
- fail();
- } catch (IOException expected) {
- }
-
- reader = new JsonReader(new StringReader("[,true]"));
- reader.beginArray();
- try {
- reader.nextNull();
- fail();
- } catch (IOException expected) {
- }
-
- reader = new JsonReader(new StringReader("[true,]"));
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- try {
- reader.nextNull();
- fail();
- } catch (IOException expected) {
- }
-
- reader = new JsonReader(new StringReader("[,]"));
- reader.beginArray();
- try {
- reader.nextNull();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientUnnecessaryArraySeparators() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[true,,true]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- reader.nextNull();
- assertEquals(true, reader.nextBoolean());
- reader.endArray();
-
- reader = new JsonReader(new StringReader("[,true]"));
- reader.setLenient(true);
- reader.beginArray();
- reader.nextNull();
- assertEquals(true, reader.nextBoolean());
- reader.endArray();
-
- reader = new JsonReader(new StringReader("[true,]"));
- reader.setLenient(true);
- reader.beginArray();
- assertEquals(true, reader.nextBoolean());
- reader.nextNull();
- reader.endArray();
-
- reader = new JsonReader(new StringReader("[,]"));
- reader.setLenient(true);
- reader.beginArray();
- reader.nextNull();
- reader.nextNull();
- reader.endArray();
- }
-
- public void testStrictMultipleTopLevelValues() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[] []"));
- reader.beginArray();
- reader.endArray();
- try {
- reader.peek();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientMultipleTopLevelValues() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[] true {}"));
- reader.setLenient(true);
- reader.beginArray();
- reader.endArray();
- assertEquals(true, reader.nextBoolean());
- reader.beginObject();
- reader.endObject();
- assertEquals(JsonToken.END_DOCUMENT, reader.peek());
- }
-
- public void testStrictTopLevelValueType() {
- JsonReader reader = new JsonReader(new StringReader("true"));
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testLenientTopLevelValueType() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("true"));
- reader.setLenient(true);
- assertEquals(true, reader.nextBoolean());
- }
-
- public void testStrictNonExecutePrefix() {
- JsonReader reader = new JsonReader(new StringReader(")]}'\n []"));
- try {
- reader.beginArray();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testBomIgnoredAsFirstCharacterOfDocument() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("\ufeff[]"));
- reader.beginArray();
- reader.endArray();
- }
-
- public void testBomForbiddenAsOtherCharacterInDocument() throws IOException {
- JsonReader reader = new JsonReader(new StringReader("[\ufeff]"));
- reader.beginArray();
- try {
- reader.endArray();
- fail();
- } catch (IOException expected) {
- }
- }
-
- public void testFailWithPosition() throws IOException {
- testFailWithPosition("Expected literal value at line 6 column 3",
- "[\n\n\n\n\n0,}]");
- }
-
- public void testFailWithPositionIsOffsetByBom() throws IOException {
- testFailWithPosition("Expected literal value at line 1 column 4",
- "\ufeff[0,}]");
- }
-
- public void testFailWithPositionGreaterThanBufferSize() throws IOException {
- String spaces = repeat(' ', 8192);
- testFailWithPosition("Expected literal value at line 6 column 3",
- "[\n\n" + spaces + "\n\n\n0,}]");
- }
-
- private void testFailWithPosition(String message, String json) throws IOException {
- JsonReader reader = new JsonReader(new StringReader(json));
- reader.beginArray();
- reader.nextInt();
- try {
- reader.peek();
- fail();
- } catch (IOException expected) {
- assertEquals(message, expected.getMessage());
- }
- }
-
- private String repeat(char c, int count) {
- char[] array = new char[count];
- Arrays.fill(array, c);
- return new String(array);
- }
-}
diff --git a/core/tests/coretests/src/android/util/JsonWriterTest.java b/core/tests/coretests/src/android/util/JsonWriterTest.java
deleted file mode 100644
index 1239a3c..0000000
--- a/core/tests/coretests/src/android/util/JsonWriterTest.java
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import junit.framework.TestCase;
-
-public final class JsonWriterTest extends TestCase {
-
- public void testWrongTopLevelType() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- try {
- jsonWriter.value("a");
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testTwoNames() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- jsonWriter.name("a");
- try {
- jsonWriter.name("a");
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testNameWithoutValue() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- jsonWriter.name("a");
- try {
- jsonWriter.endObject();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testValueWithoutName() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- try {
- jsonWriter.value(true);
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testMultipleTopLevelValues() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray().endArray();
- try {
- jsonWriter.beginArray();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testBadNestingObject() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.beginObject();
- try {
- jsonWriter.endArray();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testBadNestingArray() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.beginArray();
- try {
- jsonWriter.endObject();
- fail();
- } catch (IllegalStateException expected) {
- }
- }
-
- public void testNullName() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- try {
- jsonWriter.name(null);
- fail();
- } catch (NullPointerException expected) {
- }
- }
-
- public void testNullStringValue() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- jsonWriter.name("a");
- jsonWriter.value((String) null);
- jsonWriter.endObject();
- assertEquals("{\"a\":null}", stringWriter.toString());
- }
-
- public void testNonFiniteDoubles() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- try {
- jsonWriter.value(Double.NaN);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- jsonWriter.value(Double.NEGATIVE_INFINITY);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- jsonWriter.value(Double.POSITIVE_INFINITY);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- }
-
- public void testNonFiniteBoxedDoubles() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- try {
- jsonWriter.value(new Double(Double.NaN));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- jsonWriter.value(new Double(Double.NEGATIVE_INFINITY));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- jsonWriter.value(new Double(Double.POSITIVE_INFINITY));
- fail();
- } catch (IllegalArgumentException expected) {
- }
- }
-
- public void testDoubles() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.value(-0.0);
- jsonWriter.value(1.0);
- jsonWriter.value(Double.MAX_VALUE);
- jsonWriter.value(Double.MIN_VALUE);
- jsonWriter.value(0.0);
- jsonWriter.value(-0.5);
- jsonWriter.value(Double.MIN_NORMAL);
- jsonWriter.value(Math.PI);
- jsonWriter.value(Math.E);
- jsonWriter.endArray();
- jsonWriter.close();
- assertEquals("[-0.0,"
- + "1.0,"
- + "1.7976931348623157E308,"
- + "4.9E-324,"
- + "0.0,"
- + "-0.5,"
- + "2.2250738585072014E-308,"
- + "3.141592653589793,"
- + "2.718281828459045]", stringWriter.toString());
- }
-
- public void testLongs() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.value(0);
- jsonWriter.value(1);
- jsonWriter.value(-1);
- jsonWriter.value(Long.MIN_VALUE);
- jsonWriter.value(Long.MAX_VALUE);
- jsonWriter.endArray();
- jsonWriter.close();
- assertEquals("[0,"
- + "1,"
- + "-1,"
- + "-9223372036854775808,"
- + "9223372036854775807]", stringWriter.toString());
- }
-
- public void testNumbers() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.value(new BigInteger("0"));
- jsonWriter.value(new BigInteger("9223372036854775808"));
- jsonWriter.value(new BigInteger("-9223372036854775809"));
- jsonWriter.value(new BigDecimal("3.141592653589793238462643383"));
- jsonWriter.endArray();
- jsonWriter.close();
- assertEquals("[0,"
- + "9223372036854775808,"
- + "-9223372036854775809,"
- + "3.141592653589793238462643383]", stringWriter.toString());
- }
-
- public void testBooleans() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.value(true);
- jsonWriter.value(false);
- jsonWriter.endArray();
- assertEquals("[true,false]", stringWriter.toString());
- }
-
- public void testNulls() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.nullValue();
- jsonWriter.endArray();
- assertEquals("[null]", stringWriter.toString());
- }
-
- public void testStrings() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.value("a");
- jsonWriter.value("a\"");
- jsonWriter.value("\"");
- jsonWriter.value(":");
- jsonWriter.value(",");
- jsonWriter.value("\b");
- jsonWriter.value("\f");
- jsonWriter.value("\n");
- jsonWriter.value("\r");
- jsonWriter.value("\t");
- jsonWriter.value(" ");
- jsonWriter.value("\\");
- jsonWriter.value("{");
- jsonWriter.value("}");
- jsonWriter.value("[");
- jsonWriter.value("]");
- jsonWriter.value("\0");
- jsonWriter.value("\u0019");
- jsonWriter.endArray();
- assertEquals("[\"a\","
- + "\"a\\\"\","
- + "\"\\\"\","
- + "\":\","
- + "\",\","
- + "\"\\b\","
- + "\"\\f\","
- + "\"\\n\","
- + "\"\\r\","
- + "\"\\t\","
- + "\" \","
- + "\"\\\\\","
- + "\"{\","
- + "\"}\","
- + "\"[\","
- + "\"]\","
- + "\"\\u0000\","
- + "\"\\u0019\"]", stringWriter.toString());
- }
-
- public void testUnicodeLineBreaksEscaped() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.value("\u2028 \u2029");
- jsonWriter.endArray();
- assertEquals("[\"\\u2028 \\u2029\"]", stringWriter.toString());
- }
-
- public void testEmptyArray() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.endArray();
- assertEquals("[]", stringWriter.toString());
- }
-
- public void testEmptyObject() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- jsonWriter.endObject();
- assertEquals("{}", stringWriter.toString());
- }
-
- public void testObjectsInArrays() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginArray();
- jsonWriter.beginObject();
- jsonWriter.name("a").value(5);
- jsonWriter.name("b").value(false);
- jsonWriter.endObject();
- jsonWriter.beginObject();
- jsonWriter.name("c").value(6);
- jsonWriter.name("d").value(true);
- jsonWriter.endObject();
- jsonWriter.endArray();
- assertEquals("[{\"a\":5,\"b\":false},"
- + "{\"c\":6,\"d\":true}]", stringWriter.toString());
- }
-
- public void testArraysInObjects() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- jsonWriter.name("a");
- jsonWriter.beginArray();
- jsonWriter.value(5);
- jsonWriter.value(false);
- jsonWriter.endArray();
- jsonWriter.name("b");
- jsonWriter.beginArray();
- jsonWriter.value(6);
- jsonWriter.value(true);
- jsonWriter.endArray();
- jsonWriter.endObject();
- assertEquals("{\"a\":[5,false],"
- + "\"b\":[6,true]}", stringWriter.toString());
- }
-
- public void testDeepNestingArrays() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- for (int i = 0; i < 20; i++) {
- jsonWriter.beginArray();
- }
- for (int i = 0; i < 20; i++) {
- jsonWriter.endArray();
- }
- assertEquals("[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]", stringWriter.toString());
- }
-
- public void testDeepNestingObjects() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- for (int i = 0; i < 20; i++) {
- jsonWriter.name("a");
- jsonWriter.beginObject();
- }
- for (int i = 0; i < 20; i++) {
- jsonWriter.endObject();
- }
- jsonWriter.endObject();
- assertEquals("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":"
- + "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{"
- + "}}}}}}}}}}}}}}}}}}}}}", stringWriter.toString());
- }
-
- public void testRepeatedName() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.beginObject();
- jsonWriter.name("a").value(true);
- jsonWriter.name("a").value(false);
- jsonWriter.endObject();
- // JsonWriter doesn't attempt to detect duplicate names
- assertEquals("{\"a\":true,\"a\":false}", stringWriter.toString());
- }
-
- public void testPrettyPrintObject() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.setIndent(" ");
-
- jsonWriter.beginObject();
- jsonWriter.name("a").value(true);
- jsonWriter.name("b").value(false);
- jsonWriter.name("c").value(5.0);
- jsonWriter.name("e").nullValue();
- jsonWriter.name("f").beginArray();
- jsonWriter.value(6.0);
- jsonWriter.value(7.0);
- jsonWriter.endArray();
- jsonWriter.name("g").beginObject();
- jsonWriter.name("h").value(8.0);
- jsonWriter.name("i").value(9.0);
- jsonWriter.endObject();
- jsonWriter.endObject();
-
- String expected = "{\n"
- + " \"a\": true,\n"
- + " \"b\": false,\n"
- + " \"c\": 5.0,\n"
- + " \"e\": null,\n"
- + " \"f\": [\n"
- + " 6.0,\n"
- + " 7.0\n"
- + " ],\n"
- + " \"g\": {\n"
- + " \"h\": 8.0,\n"
- + " \"i\": 9.0\n"
- + " }\n"
- + "}";
- assertEquals(expected, stringWriter.toString());
- }
-
- public void testPrettyPrintArray() throws IOException {
- StringWriter stringWriter = new StringWriter();
- JsonWriter jsonWriter = new JsonWriter(stringWriter);
- jsonWriter.setIndent(" ");
-
- jsonWriter.beginArray();
- jsonWriter.value(true);
- jsonWriter.value(false);
- jsonWriter.value(5.0);
- jsonWriter.nullValue();
- jsonWriter.beginObject();
- jsonWriter.name("a").value(6.0);
- jsonWriter.name("b").value(7.0);
- jsonWriter.endObject();
- jsonWriter.beginArray();
- jsonWriter.value(8.0);
- jsonWriter.value(9.0);
- jsonWriter.endArray();
- jsonWriter.endArray();
-
- String expected = "[\n"
- + " true,\n"
- + " false,\n"
- + " 5.0,\n"
- + " null,\n"
- + " {\n"
- + " \"a\": 6.0,\n"
- + " \"b\": 7.0\n"
- + " },\n"
- + " [\n"
- + " 8.0,\n"
- + " 9.0\n"
- + " ]\n"
- + "]";
- assertEquals(expected, stringWriter.toString());
- }
-}
diff --git a/core/tests/overlaytests/OverlayAppFirst/Android.mk b/core/tests/overlaytests/OverlayAppFirst/Android.mk
new file mode 100644
index 0000000..ee991fc
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.first_app_overlay
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayAppFirst/AndroidManifest.xml b/core/tests/overlaytests/OverlayAppFirst/AndroidManifest.xml
new file mode 100644
index 0000000..ec10bbc
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.first_app_overlay"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="com.android.overlaytest" android:priority="1"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg b/core/tests/overlaytests/OverlayAppFirst/res/drawable-nodpi/drawable.jpg
similarity index 100%
rename from core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg
rename to core/tests/overlaytests/OverlayAppFirst/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayAppFirst/res/raw/lorem_ipsum.txt
new file mode 100644
index 0000000..756b0a3
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/raw/lorem_ipsum.txt
@@ -0,0 +1 @@
+Lorem ipsum: single overlay.
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/values-sv/config.xml b/core/tests/overlaytests/OverlayAppFirst/res/values-sv/config.xml
new file mode 100644
index 0000000..9cdc73e
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/values-sv/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="matrix_100100">400</integer>
+ <integer name="matrix_100101">400</integer>
+ <integer name="matrix_100110">400</integer>
+ <integer name="matrix_100111">400</integer>
+ <integer name="matrix_101100">400</integer>
+ <integer name="matrix_101101">400</integer>
+ <integer name="matrix_101110">400</integer>
+ <integer name="matrix_101111">400</integer>
+ <integer name="matrix_110100">400</integer>
+ <integer name="matrix_110101">400</integer>
+ <integer name="matrix_110110">400</integer>
+ <integer name="matrix_110111">400</integer>
+ <integer name="matrix_111100">400</integer>
+ <integer name="matrix_111101">400</integer>
+ <integer name="matrix_111110">400</integer>
+ <integer name="matrix_111111">400</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/values/config.xml b/core/tests/overlaytests/OverlayAppFirst/res/values/config.xml
new file mode 100644
index 0000000..972137a
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/values/config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="str">single</string>
+ <string name="str2">single</string>
+ <integer name="matrix_101000">300</integer>
+ <integer name="matrix_101001">300</integer>
+ <integer name="matrix_101010">300</integer>
+ <integer name="matrix_101011">300</integer>
+ <integer name="matrix_101100">300</integer>
+ <integer name="matrix_101101">300</integer>
+ <integer name="matrix_101110">300</integer>
+ <integer name="matrix_101111">300</integer>
+ <integer name="matrix_111000">300</integer>
+ <integer name="matrix_111001">300</integer>
+ <integer name="matrix_111010">300</integer>
+ <integer name="matrix_111011">300</integer>
+ <integer name="matrix_111100">300</integer>
+ <integer name="matrix_111101">300</integer>
+ <integer name="matrix_111110">300</integer>
+ <integer name="matrix_111111">300</integer>
+ <bool name="usually_false">true</bool>
+ <integer-array name="fibonacci">
+ <item>21</item>
+ <item>13</item>
+ <item>8</item>
+ <item>5</item>
+ <item>3</item>
+ <item>2</item>
+ <item>1</item>
+ <item>1</item>
+ </integer-array>
+ <!-- The following integer does not exist in the original package. Idmap
+ generation should therefore ignore it. -->
+ <integer name="integer_not_in_original_package">0</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppFirst/res/xml/integer.xml b/core/tests/overlaytests/OverlayAppFirst/res/xml/integer.xml
new file mode 100644
index 0000000..7f628d9
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppFirst/res/xml/integer.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<integer value="1"/>
diff --git a/core/tests/overlaytests/OverlayAppSecond/Android.mk b/core/tests/overlaytests/OverlayAppSecond/Android.mk
new file mode 100644
index 0000000..87402c43
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.second_app_overlay
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayAppSecond/AndroidManifest.xml b/core/tests/overlaytests/OverlayAppSecond/AndroidManifest.xml
new file mode 100644
index 0000000..ed49863
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.second_app_overlay"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="com.android.overlaytest" android:priority="2"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayAppSecond/res/raw/lorem_ipsum.txt
new file mode 100644
index 0000000..613f5b6
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/raw/lorem_ipsum.txt
@@ -0,0 +1 @@
+Lorem ipsum: multiple overlays.
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/values-sv/config.xml b/core/tests/overlaytests/OverlayAppSecond/res/values-sv/config.xml
new file mode 100644
index 0000000..ec4b6c0
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/values-sv/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="matrix_100001">600</integer>
+ <integer name="matrix_100011">600</integer>
+ <integer name="matrix_100101">600</integer>
+ <integer name="matrix_100111">600</integer>
+ <integer name="matrix_101001">600</integer>
+ <integer name="matrix_101011">600</integer>
+ <integer name="matrix_101101">600</integer>
+ <integer name="matrix_101111">600</integer>
+ <integer name="matrix_110001">600</integer>
+ <integer name="matrix_110011">600</integer>
+ <integer name="matrix_110101">600</integer>
+ <integer name="matrix_110111">600</integer>
+ <integer name="matrix_111001">600</integer>
+ <integer name="matrix_111011">600</integer>
+ <integer name="matrix_111101">600</integer>
+ <integer name="matrix_111111">600</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/values/config.xml b/core/tests/overlaytests/OverlayAppSecond/res/values/config.xml
new file mode 100644
index 0000000..8b07216
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="str">multiple</string>
+ <integer name="matrix_100010">500</integer>
+ <integer name="matrix_100011">500</integer>
+ <integer name="matrix_100110">500</integer>
+ <integer name="matrix_100111">500</integer>
+ <integer name="matrix_101010">500</integer>
+ <integer name="matrix_101011">500</integer>
+ <integer name="matrix_101110">500</integer>
+ <integer name="matrix_101111">500</integer>
+ <integer name="matrix_110010">500</integer>
+ <integer name="matrix_110011">500</integer>
+ <integer name="matrix_110110">500</integer>
+ <integer name="matrix_110111">500</integer>
+ <integer name="matrix_111010">500</integer>
+ <integer name="matrix_111011">500</integer>
+ <integer name="matrix_111110">500</integer>
+ <integer name="matrix_111111">500</integer>
+ <bool name="usually_false">false</bool>
+</resources>
diff --git a/core/tests/overlaytests/OverlayAppSecond/res/xml/integer.xml b/core/tests/overlaytests/OverlayAppSecond/res/xml/integer.xml
new file mode 100644
index 0000000..f3370a6
--- /dev/null
+++ b/core/tests/overlaytests/OverlayAppSecond/res/xml/integer.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<integer value="2"/>
diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk
index f7f67f6..4767e52 100644
--- a/core/tests/overlaytests/OverlayTest/Android.mk
+++ b/core/tests/overlaytests/OverlayTest/Android.mk
@@ -5,6 +5,10 @@
LOCAL_PACKAGE_NAME := OverlayTest
+LOCAL_DEX_PREOPT := false
+
+LOCAL_MODULE_PATH := $(TARGET_OUT)/app
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTest/res/drawable-nodpi/drawable.jpg b/core/tests/overlaytests/OverlayTest/res/drawable-nodpi/drawable.jpg
new file mode 100644
index 0000000..a3f14f3
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/drawable-nodpi/drawable.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayTest/res/raw/lorem_ipsum.txt b/core/tests/overlaytests/OverlayTest/res/raw/lorem_ipsum.txt
new file mode 100644
index 0000000..cee7a92
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/raw/lorem_ipsum.txt
@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
diff --git a/core/tests/overlaytests/OverlayTest/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTest/res/values-sv/config.xml
new file mode 100644
index 0000000..891853e
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/values-sv/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <integer name="matrix_110000">200</integer>
+ <integer name="matrix_110001">200</integer>
+ <integer name="matrix_110010">200</integer>
+ <integer name="matrix_110011">200</integer>
+ <integer name="matrix_110100">200</integer>
+ <integer name="matrix_110101">200</integer>
+ <integer name="matrix_110110">200</integer>
+ <integer name="matrix_110111">200</integer>
+ <integer name="matrix_111000">200</integer>
+ <integer name="matrix_111001">200</integer>
+ <integer name="matrix_111010">200</integer>
+ <integer name="matrix_111011">200</integer>
+ <integer name="matrix_111100">200</integer>
+ <integer name="matrix_111101">200</integer>
+ <integer name="matrix_111110">200</integer>
+ <integer name="matrix_111111">200</integer>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTest/res/values/config.xml b/core/tests/overlaytests/OverlayTest/res/values/config.xml
new file mode 100644
index 0000000..c692a262
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/values/config.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="str">none</string>
+ <string name="str2">none</string>
+ <integer name="matrix_100000">100</integer>
+ <integer name="matrix_100001">100</integer>
+ <integer name="matrix_100010">100</integer>
+ <integer name="matrix_100011">100</integer>
+ <integer name="matrix_100100">100</integer>
+ <integer name="matrix_100101">100</integer>
+ <integer name="matrix_100110">100</integer>
+ <integer name="matrix_100111">100</integer>
+ <integer name="matrix_101000">100</integer>
+ <integer name="matrix_101001">100</integer>
+ <integer name="matrix_101010">100</integer>
+ <integer name="matrix_101011">100</integer>
+ <integer name="matrix_101100">100</integer>
+ <integer name="matrix_101101">100</integer>
+ <integer name="matrix_101110">100</integer>
+ <integer name="matrix_101111">100</integer>
+ <integer name="matrix_110000">100</integer>
+ <integer name="matrix_110001">100</integer>
+ <integer name="matrix_110010">100</integer>
+ <integer name="matrix_110011">100</integer>
+ <integer name="matrix_110100">100</integer>
+ <integer name="matrix_110101">100</integer>
+ <integer name="matrix_110110">100</integer>
+ <integer name="matrix_110111">100</integer>
+ <integer name="matrix_111000">100</integer>
+ <integer name="matrix_111001">100</integer>
+ <integer name="matrix_111010">100</integer>
+ <integer name="matrix_111011">100</integer>
+ <integer name="matrix_111100">100</integer>
+ <integer name="matrix_111101">100</integer>
+ <integer name="matrix_111110">100</integer>
+ <integer name="matrix_111111">100</integer>
+ <bool name="usually_false">false</bool>
+ <bool name="always_true">true</bool>
+ <integer-array name="fibonacci">
+ <item>1</item>
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ <item>5</item>
+ <item>8</item>
+ <item>13</item>
+ <item>21</item>
+ </integer-array>
+ <integer-array name="prime_numbers">
+ <item>2</item>
+ <item>3</item>
+ <item>5</item>
+ <item>7</item>
+ <item>11</item>
+ <item>13</item>
+ <item>17</item>
+ <item>19</item>
+ </integer-array>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTest/res/xml/integer.xml b/core/tests/overlaytests/OverlayTest/res/xml/integer.xml
new file mode 100644
index 0000000..9383daa
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/res/xml/integer.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<integer value="0"/>
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
index 6211c1c..58b7db9 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -2,13 +2,21 @@
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import android.test.AndroidTestCase;
+import android.util.AttributeSet;
+import android.util.Xml;
+import java.io.BufferedReader;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.util.Locale;
public abstract class OverlayBaseTest extends AndroidTestCase {
private Resources mResources;
- protected boolean mWithOverlay; // will be set by subclasses
+ protected int mMode; // will be set by subclasses
+ static final protected int MODE_NO_OVERLAY = 0;
+ static final protected int MODE_SINGLE_OVERLAY = 1;
+ static final protected int MODE_MULTIPLE_OVERLAYS = 2;
protected void setUp() {
mResources = getContext().getResources();
@@ -36,20 +44,82 @@
mResources.updateConfiguration(config, mResources.getDisplayMetrics());
}
- private void assertResource(int resId, boolean ewo, boolean ew) throws Throwable {
- boolean expected = mWithOverlay ? ew : ewo;
+ private boolean getExpected(boolean no, boolean so, boolean mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private String getExpected(String no, String so, String mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private int getExpected(int no, int so, int mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private int[] getExpected(int[] no, int[] so, int[] mo) {
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ return no;
+ case MODE_SINGLE_OVERLAY:
+ return so;
+ case MODE_MULTIPLE_OVERLAYS:
+ return mo;
+ default:
+ fail("Unknown mode!");
+ return no;
+ }
+ }
+
+ private void assertResource(int resId, boolean no, boolean so, boolean mo) throws Throwable {
+ boolean expected = getExpected(no, so, mo);
boolean actual = mResources.getBoolean(resId);
assertEquals(expected, actual);
}
- private void assertResource(int resId, String ewo, String ew) throws Throwable {
- String expected = mWithOverlay ? ew : ewo;
+ private void assertResource(int resId, int no, int so, int mo) throws Throwable {
+ int expected = getExpected(no, so, mo);
+ int actual = mResources.getInteger(resId);
+ assertEquals(expected, actual);
+ }
+
+ private void assertResource(int resId, String no, String so, String mo) throws Throwable {
+ String expected = getExpected(no, so, mo);
String actual = mResources.getString(resId);
assertEquals(expected, actual);
}
- private void assertResource(int resId, int[] ewo, int[] ew) throws Throwable {
- int[] expected = mWithOverlay ? ew : ewo;
+ private void assertResource(int resId, int[] no, int[] so, int[] mo) throws Throwable {
+ int[] expected = getExpected(no, so, mo);
int[] actual = mResources.getIntArray(resId);
assertEquals("length:", expected.length, actual.length);
for (int i = 0; i < actual.length; ++i) {
@@ -57,62 +127,334 @@
}
}
+ public void testFrameworkBooleanOverlay() throws Throwable {
+ // config_annoy_dianne has the value:
+ // - true when no overlay exists (MODE_NO_OVERLAY)
+ // - false when a single overlay exists (MODE_SINGLE_OVERLAY)
+ // - false when multiple overlays exists (MODE_MULTIPLE_OVERLAYS)
+ final int resId = com.android.internal.R.bool.config_annoy_dianne;
+ assertResource(resId, true, false, false);
+ }
+
public void testBooleanOverlay() throws Throwable {
- // config_automatic_brightness_available has overlay (default config)
- final int resId = com.android.internal.R.bool.config_automatic_brightness_available;
- assertResource(resId, false, true);
+ // usually_false has the value:
+ // - false when no overlay exists (MODE_NO_OVERLAY)
+ // - true when a single overlay exists (MODE_SINGLE_OVERLAY)
+ // - false when multiple overlays exists (MODE_MULTIPLE_OVERLAYS)
+ final int resId = R.bool.usually_false;
+ assertResource(resId, false, true, false);
}
public void testBoolean() throws Throwable {
- // config_annoy_dianne has no overlay
- final int resId = com.android.internal.R.bool.config_annoy_dianne;
- assertResource(resId, true, true);
- }
-
- public void testStringOverlay() throws Throwable {
- // phoneTypeCar has an overlay (default config), which shouldn't shadow
- // the Swedish translation
- final int resId = com.android.internal.R.string.phoneTypeCar;
- setLocale("sv_SE");
- assertResource(resId, "Bil", "Bil");
- }
-
- public void testStringSwedishOverlay() throws Throwable {
- // phoneTypeWork has overlay (no default config, only for lang=sv)
- final int resId = com.android.internal.R.string.phoneTypeWork;
- setLocale("en_US");
- assertResource(resId, "Work", "Work");
- setLocale("sv_SE");
- assertResource(resId, "Arbete", "Jobb");
- }
-
- public void testString() throws Throwable {
- // phoneTypeHome has no overlay
- final int resId = com.android.internal.R.string.phoneTypeHome;
- setLocale("en_US");
- assertResource(resId, "Home", "Home");
- setLocale("sv_SE");
- assertResource(resId, "Hem", "Hem");
+ // always_true has no overlay
+ final int resId = R.bool.always_true;
+ assertResource(resId, true, true, true);
}
public void testIntegerArrayOverlay() throws Throwable {
- // config_scrollBarrierVibePattern has overlay (default config)
- final int resId = com.android.internal.R.array.config_scrollBarrierVibePattern;
- assertResource(resId, new int[]{0, 15, 10, 10}, new int[]{100, 200, 300});
+ // fibonacci has values:
+ // - eight first values of Fibonacci sequence, when no overlay exists (MODE_NO_OVERLAY)
+ // - eight first values of Fibonacci sequence (reversed), for single and multiple overlays
+ // (MODE_SINGLE_OVERLAY, MODE_MULTIPLE_OVERLAYS)
+ final int resId = R.array.fibonacci;
+ assertResource(resId,
+ new int[]{1, 1, 2, 3, 5, 8, 13, 21},
+ new int[]{21, 13, 8, 5, 3, 2, 1, 1},
+ new int[]{21, 13, 8, 5, 3, 2, 1, 1});
}
public void testIntegerArray() throws Throwable {
- // config_virtualKeyVibePattern has no overlay
- final int resId = com.android.internal.R.array.config_virtualKeyVibePattern;
- final int[] expected = {0, 10, 20, 30};
- assertResource(resId, expected, expected);
+ // prime_numbers has no overlay
+ final int resId = R.array.prime_numbers;
+ final int[] expected = {2, 3, 5, 7, 11, 13, 17, 19};
+ assertResource(resId, expected, expected, expected);
}
- public void testAsset() throws Throwable {
- // drawable/default_background.jpg has overlay (default config)
- final int resId = com.android.internal.R.drawable.default_wallpaper;
+ public void testDrawable() throws Throwable {
+ // drawable-nodpi/drawable has overlay (default config)
+ final int resId = R.drawable.drawable;
int actual = calculateRawResourceChecksum(resId);
- int expected = mWithOverlay ? 0x000051da : 0x0014ebce;
+ int expected = 0;
+ switch (mMode) {
+ case MODE_NO_OVERLAY:
+ expected = 0x00005665;
+ break;
+ case MODE_SINGLE_OVERLAY:
+ case MODE_MULTIPLE_OVERLAYS:
+ expected = 0x000051da;
+ break;
+ default:
+ fail("Unknown mode " + mMode);
+ }
assertEquals(expected, actual);
}
+
+ public void testAppString() throws Throwable {
+ final int resId = R.string.str;
+ assertResource(resId, "none", "single", "multiple");
+ }
+
+ public void testApp2() throws Throwable {
+ final int resId = R.string.str2; // only in base package and first app overlay
+ assertResource(resId, "none", "single", "single");
+ }
+
+ public void testAppXml() throws Throwable {
+ int expected = getExpected(0, 1, 2);
+ int actual = -1;
+ XmlResourceParser parser = mResources.getXml(R.xml.integer);
+ int type = parser.getEventType();
+ while (type != XmlResourceParser.END_DOCUMENT && actual == -1) {
+ if (type == XmlResourceParser.START_TAG && "integer".equals(parser.getName())) {
+ AttributeSet as = Xml.asAttributeSet(parser);
+ actual = as.getAttributeIntValue(null, "value", -1);
+ }
+ type = parser.next();
+ }
+ parser.close();
+ assertEquals(expected, actual);
+ }
+
+ public void testAppRaw() throws Throwable {
+ final int resId = R.raw.lorem_ipsum;
+
+ InputStream input = null;
+ BufferedReader reader = null;
+ String actual = "";
+ try {
+ input = mResources.openRawResource(resId);
+ reader = new BufferedReader(new InputStreamReader(input));
+ actual = reader.readLine();
+ } finally {
+ reader.close();
+ input.close();
+ }
+
+ final String no = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, " +
+ "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " +
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip " +
+ "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit " +
+ "esse cillum dolore eu fugiat nulla pariatur. " +
+ "Excepteur sint occaecat cupidatat non proident, " +
+ "sunt in culpa qui officia deserunt mollit anim id est laborum.";
+ final String so = "Lorem ipsum: single overlay.";
+ final String mo = "Lorem ipsum: multiple overlays.";
+
+ assertEquals(getExpected(no, so, mo), actual);
+ }
+
+ /*
+ * testMatrix* tests
+ *
+ * The naming convention textMatrixABCDEF refers to in which packages and
+ * which configurations a resource is defined (1 if the resource is
+ * defined). If defined, a slot is always given the same value.
+ *
+ * SLOT PACKAGE CONFIGURATION VALUE
+ * A target package (default) 100
+ * B target package -sv 200
+ * C OverlayAppFirst (default) 300
+ * D OverlayAppFirst -sv 400
+ * E OverlayAppSecond (default) 500
+ * F OverlayAppSecond -sv 600
+ *
+ * Example: in testMatrix101110, the base package defines the
+ * R.integer.matrix101110 resource for the default configuration (value
+ * 100), OverlayAppFirst defines it for both default and Swedish
+ * configurations (values 300 and 400, respectively), and OverlayAppSecond
+ * defines it for the default configuration (value 500). If both overlays
+ * are loaded, the expected value after setting the language to Swedish is
+ * 400.
+ */
+ public void testMatrix100000() throws Throwable {
+ final int resId = R.integer.matrix_100000;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 100);
+ }
+
+ public void testMatrix100001() throws Throwable {
+ final int resId = R.integer.matrix_100001;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 600);
+ }
+
+ public void testMatrix100010() throws Throwable {
+ final int resId = R.integer.matrix_100010;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 500);
+ }
+
+ public void testMatrix100011() throws Throwable {
+ final int resId = R.integer.matrix_100011;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 100, 600);
+ }
+
+ public void testMatrix100100() throws Throwable {
+ final int resId = R.integer.matrix_100100;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix100101() throws Throwable {
+ final int resId = R.integer.matrix_100101;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix100110() throws Throwable {
+ final int resId = R.integer.matrix_100110;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix100111() throws Throwable {
+ final int resId = R.integer.matrix_100111;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix101000() throws Throwable {
+ final int resId = R.integer.matrix_101000;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 300);
+ }
+
+ public void testMatrix101001() throws Throwable {
+ final int resId = R.integer.matrix_101001;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 600);
+ }
+
+ public void testMatrix101010() throws Throwable {
+ final int resId = R.integer.matrix_101010;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 500);
+ }
+
+ public void testMatrix101011() throws Throwable {
+ final int resId = R.integer.matrix_101011;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 300, 600);
+ }
+
+ public void testMatrix101100() throws Throwable {
+ final int resId = R.integer.matrix_101100;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix101101() throws Throwable {
+ final int resId = R.integer.matrix_101101;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix101110() throws Throwable {
+ final int resId = R.integer.matrix_101110;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 400);
+ }
+
+ public void testMatrix101111() throws Throwable {
+ final int resId = R.integer.matrix_101111;
+ setLocale("sv_SE");
+ assertResource(resId, 100, 400, 600);
+ }
+
+ public void testMatrix110000() throws Throwable {
+ final int resId = R.integer.matrix_110000;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix110001() throws Throwable {
+ final int resId = R.integer.matrix_110001;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix110010() throws Throwable {
+ final int resId = R.integer.matrix_110010;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix110011() throws Throwable {
+ final int resId = R.integer.matrix_110011;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix110100() throws Throwable {
+ final int resId = R.integer.matrix_110100;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix110101() throws Throwable {
+ final int resId = R.integer.matrix_110101;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
+
+ public void testMatrix110110() throws Throwable {
+ final int resId = R.integer.matrix_110110;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix110111() throws Throwable {
+ final int resId = R.integer.matrix_110111;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
+
+ public void testMatrix111000() throws Throwable {
+ final int resId = R.integer.matrix_111000;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix111001() throws Throwable {
+ final int resId = R.integer.matrix_111001;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix111010() throws Throwable {
+ final int resId = R.integer.matrix_111010;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 200);
+ }
+
+ public void testMatrix111011() throws Throwable {
+ final int resId = R.integer.matrix_111011;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 200, 600);
+ }
+
+ public void testMatrix111100() throws Throwable {
+ final int resId = R.integer.matrix_111100;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix111101() throws Throwable {
+ final int resId = R.integer.matrix_111101;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
+
+ public void testMatrix111110() throws Throwable {
+ final int resId = R.integer.matrix_111110;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 400);
+ }
+
+ public void testMatrix111111() throws Throwable {
+ final int resId = R.integer.matrix_111111;
+ setLocale("sv_SE");
+ assertResource(resId, 200, 400, 600);
+ }
}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
new file mode 100644
index 0000000..e104f5a
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithMultipleOverlaysTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithMultipleOverlaysTest extends OverlayBaseTest {
+ public WithMultipleOverlaysTest() {
+ mMode = MODE_MULTIPLE_OVERLAYS;
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
index 1292d03..816a476 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
@@ -2,6 +2,6 @@
public class WithOverlayTest extends OverlayBaseTest {
public WithOverlayTest() {
- mWithOverlay = true;
+ mMode = MODE_SINGLE_OVERLAY;
}
}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
index 630ff8f..318cccc 100644
--- a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -2,6 +2,6 @@
public class WithoutOverlayTest extends OverlayBaseTest {
public WithoutOverlayTest() {
- mWithOverlay = false;
+ mMode = MODE_NO_OVERLAY;
}
}
diff --git a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
index bcbb0d1..f8b6c7b 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
@@ -2,5 +2,5 @@
package="com.android.overlaytest.overlay"
android:versionCode="1"
android:versionName="1.0">
- <overlay-package android:name="android"/>
+ <overlay android:targetPackage="android" android:priority="1"/>
</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
deleted file mode 100644
index bc52367..0000000
--- a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="phoneTypeWork">Jobb</string>
-</resources>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
index 794f475..c1e3de1 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
@@ -1,13 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <bool name="config_automatic_brightness_available">true</bool>
- <string name="phoneTypeCar">Automobile</string>
- <integer-array name="config_scrollBarrierVibePattern">
- <item>100</item>
- <item>200</item>
- <item>300</item>
- </integer-array>
- <!-- The following integer does not exist in the original package. Idmap
- generation should therefore ignore it. -->
- <integer name="integer_not_in_original_package">0</integer>
+ <bool name="config_annoy_dianne">false</bool>
</resources>
diff --git a/core/tests/overlaytests/README b/core/tests/overlaytests/README
deleted file mode 100644
index 4b3e6f2..0000000
--- a/core/tests/overlaytests/README
+++ /dev/null
@@ -1,15 +0,0 @@
-Unit tests for runtime resource overlay
-=======================================
-
-As of this writing, runtime resource overlay is only triggered for
-/system/framework/framework-res.apk. Because of this, installation of
-overlay packages require the Android platform be rebooted. However, the
-regular unit tests (triggered via development/testrunner/runtest.py)
-cannot handle reboots. As a workaround, this directory contains a shell
-script which will trigger the tests in a non-standard way.
-
-Once runtime resource overlay may be applied to applications, the tests
-in this directory should be moved to core/tests/coretests. Also, by
-applying runtime resource overlay to a dedicated test application, the
-test cases would not need to assume default values for non-overlaid
-resources.
diff --git a/core/tests/overlaytests/runtests.sh b/core/tests/overlaytests/runtests.sh
deleted file mode 100755
index 0a721ad40..0000000
--- a/core/tests/overlaytests/runtests.sh
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/bin/bash
-
-adb="adb"
-if [[ $# -gt 0 ]]; then
- adb="adb $*" # for setting -e, -d or -s <serial>
-fi
-
-function atexit()
-{
- local retval=$?
-
- if [[ $retval -eq 0 ]]; then
- rm $log
- else
- echo "There were errors, please check log at $log"
- fi
-}
-
-log=$(mktemp)
-trap "atexit" EXIT
-
-function compile_module()
-{
- local android_mk="$1"
-
- echo "Compiling .${android_mk:${#PWD}}"
- ONE_SHOT_MAKEFILE="$android_mk" make -C "../../../../../" files | tee -a $log
- if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
- exit 1
- fi
-}
-
-function wait_for_boot_completed()
-{
- echo "Rebooting device"
- $adb wait-for-device logcat -c
- $adb wait-for-device logcat | grep -m 1 -e 'PowerManagerService.*bootCompleted' >/dev/null
-}
-
-function mkdir_if_needed()
-{
- local path="$1"
-
- if [[ "${path:0:1}" != "/" ]]; then
- echo "mkdir_if_needed: error: path '$path' does not begin with /" | tee -a $log
- exit 1
- fi
-
- local basename=$(basename "$path")
- local dirname=$(dirname "$path")
- local t=$($adb shell ls -l $dirname | tr -d '\r' | grep -e "${basename}$" | grep -oe '^.')
-
- case "$t" in
- d) # File exists, and is a directory ...
- # do nothing
- ;;
- l) # ... (or symbolic link possibly to a directory).
- # do nothing
- ;;
- "") # File does not exist.
- mkdir_if_needed "$dirname"
- $adb shell mkdir "$path"
- ;;
- *) # File exists, but is not a directory.
- echo "mkdir_if_needed: file '$path' exists, but is not a directory" | tee -a $log
- exit 1
- ;;
- esac
-}
-
-function disable_overlay()
-{
- echo "Disabling overlay"
- $adb shell rm /vendor/overlay/framework/framework-res.apk
- $adb shell rm /data/resource-cache/vendor@overlay@framework@framework-res.apk@idmap
-}
-
-function enable_overlay()
-{
- echo "Enabling overlay"
- mkdir_if_needed "/system/vendor"
- mkdir_if_needed "/vendor/overlay/framework"
- $adb shell ln -s /data/app/com.android.overlaytest.overlay.apk /vendor/overlay/framework/framework-res.apk
-}
-
-function instrument()
-{
- local class="$1"
-
- echo "Instrumenting $class"
- $adb shell am instrument -w -e class $class com.android.overlaytest/android.test.InstrumentationTestRunner | tee -a $log
-}
-
-function remount()
-{
- echo "Remounting file system writable"
- $adb remount | tee -a $log
-}
-
-function sync()
-{
- echo "Syncing to device"
- $adb sync data | tee -a $log
-}
-
-# some commands require write access, remount once and for all
-remount
-
-# build and sync
-compile_module "$PWD/OverlayTest/Android.mk"
-compile_module "$PWD/OverlayTestOverlay/Android.mk"
-sync
-
-# instrument test (without overlay)
-$adb shell stop
-disable_overlay
-$adb shell start
-wait_for_boot_completed
-instrument "com.android.overlaytest.WithoutOverlayTest"
-
-# instrument test (with overlay)
-$adb shell stop
-enable_overlay
-$adb shell start
-wait_for_boot_completed
-instrument "com.android.overlaytest.WithOverlayTest"
-
-# cleanup
-exit $(grep -c -e '^FAILURES' $log)
diff --git a/core/tests/overlaytests/testrunner.py b/core/tests/overlaytests/testrunner.py
new file mode 100755
index 0000000..4f94373
--- /dev/null
+++ b/core/tests/overlaytests/testrunner.py
@@ -0,0 +1,679 @@
+#!/usr/bin/python
+import hashlib
+import optparse
+import os
+import re
+import shlex
+import subprocess
+import sys
+import threading
+import time
+
+TASK_COMPILATION = 'compile'
+TASK_DISABLE_OVERLAYS = 'disable overlays'
+TASK_ENABLE_MULTIPLE_OVERLAYS = 'enable multiple overlays'
+TASK_ENABLE_SINGLE_OVERLAY = 'enable single overlay'
+TASK_FILE_EXISTS_TEST = 'test (file exists)'
+TASK_GREP_IDMAP_TEST = 'test (grep idmap)'
+TASK_MD5_TEST = 'test (md5)'
+TASK_IDMAP_PATH = 'idmap --path'
+TASK_IDMAP_SCAN = 'idmap --scan'
+TASK_INSTRUMENTATION = 'instrumentation'
+TASK_INSTRUMENTATION_TEST = 'test (instrumentation)'
+TASK_MKDIR = 'mkdir'
+TASK_PUSH = 'push'
+TASK_ROOT = 'root'
+TASK_REMOUNT = 'remount'
+TASK_RM = 'rm'
+TASK_SETUP_IDMAP_PATH = 'setup idmap --path'
+TASK_SETUP_IDMAP_SCAN = 'setup idmap --scan'
+TASK_START = 'start'
+TASK_STOP = 'stop'
+
+adb = 'adb'
+
+def _adb_shell(cmd):
+ argv = shlex.split(adb + " shell '" + cmd + "; echo $?'")
+ proc = subprocess.Popen(argv, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ (stdout, stderr) = (stdout.replace('\r', ''), stderr.replace('\r', ''))
+ tmp = stdout.rsplit('\n', 2)
+ if len(tmp) == 2:
+ stdout == ''
+ returncode = int(tmp[0])
+ else:
+ stdout = tmp[0] + '\n'
+ returncode = int(tmp[1])
+ return returncode, stdout, stderr
+
+class VerbosePrinter:
+ class Ticker(threading.Thread):
+ def _print(self):
+ s = '\r' + self.text + '[' + '.' * self.i + ' ' * (4 - self.i) + ']'
+ sys.stdout.write(s)
+ sys.stdout.flush()
+ self.i = (self.i + 1) % 5
+
+ def __init__(self, cond_var, text):
+ threading.Thread.__init__(self)
+ self.text = text
+ self.setDaemon(True)
+ self.cond_var = cond_var
+ self.running = False
+ self.i = 0
+ self._print()
+ self.running = True
+
+ def run(self):
+ self.cond_var.acquire()
+ while True:
+ self.cond_var.wait(0.25)
+ running = self.running
+ if not running:
+ break
+ self._print()
+ self.cond_var.release()
+
+ def stop(self):
+ self.cond_var.acquire()
+ self.running = False
+ self.cond_var.notify_all()
+ self.cond_var.release()
+
+ def _start_ticker(self):
+ self.ticker = VerbosePrinter.Ticker(self.cond_var, self.text)
+ self.ticker.start()
+
+ def _stop_ticker(self):
+ self.ticker.stop()
+ self.ticker.join()
+ self.ticker = None
+
+ def _format_begin(self, type, name):
+ N = self.width - len(type) - len(' [ ] ')
+ fmt = '%%s %%-%ds ' % N
+ return fmt % (type, name)
+
+ def __init__(self, use_color):
+ self.cond_var = threading.Condition()
+ self.ticker = None
+ if use_color:
+ self.color_RED = '\033[1;31m'
+ self.color_red = '\033[0;31m'
+ self.color_reset = '\033[0;37m'
+ else:
+ self.color_RED = ''
+ self.color_red = ''
+ self.color_reset = ''
+
+ argv = shlex.split('stty size') # get terminal width
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ if proc.returncode == 0:
+ (h, w) = stdout.split()
+ self.width = int(w)
+ else:
+ self.width = 72 # conservative guesstimate
+
+ def begin(self, type, name):
+ self.text = self._format_begin(type, name)
+ sys.stdout.write(self.text + '[ ]')
+ sys.stdout.flush()
+ self._start_ticker()
+
+ def end_pass(self, type, name):
+ self._stop_ticker()
+ sys.stdout.write('\r' + self.text + '[ OK ]\n')
+ sys.stdout.flush()
+
+ def end_fail(self, type, name, msg):
+ self._stop_ticker()
+ sys.stdout.write('\r' + self.color_RED + self.text + '[FAIL]\n')
+ sys.stdout.write(self.color_red)
+ sys.stdout.write(msg)
+ sys.stdout.write(self.color_reset)
+ sys.stdout.flush()
+
+class QuietPrinter:
+ def begin(self, type, name):
+ pass
+
+ def end_pass(self, type, name):
+ sys.stdout.write('PASS ' + type + ' ' + name + '\n')
+ sys.stdout.flush()
+
+ def end_fail(self, type, name, msg):
+ sys.stdout.write('FAIL ' + type + ' ' + name + '\n')
+ sys.stdout.flush()
+
+class CompilationTask:
+ def __init__(self, makefile):
+ self.makefile = makefile
+
+ def get_type(self):
+ return TASK_COMPILATION
+
+ def get_name(self):
+ return self.makefile
+
+ def execute(self):
+ os.putenv('ONE_SHOT_MAKEFILE', os.getcwd() + "/" + self.makefile)
+ argv = shlex.split('make -C "../../../../../" files')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ return proc.returncode, stdout, stderr
+
+class InstrumentationTask:
+ def __init__(self, instrumentation_class):
+ self.instrumentation_class = instrumentation_class
+
+ def get_type(self):
+ return TASK_INSTRUMENTATION
+
+ def get_name(self):
+ return self.instrumentation_class
+
+ def execute(self):
+ return _adb_shell('am instrument -r -w -e class %s com.android.overlaytest/android.test.InstrumentationTestRunner' % self.instrumentation_class)
+
+class PushTask:
+ def __init__(self, src, dest):
+ self.src = src
+ self.dest = dest
+
+ def get_type(self):
+ return TASK_PUSH
+
+ def get_name(self):
+ return "%s -> %s" % (self.src, self.dest)
+
+ def execute(self):
+ src = os.getenv('OUT') + "/" + self.src
+ argv = shlex.split(adb + ' push %s %s' % (src, self.dest))
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ return proc.returncode, stdout, stderr
+
+class MkdirTask:
+ def __init__(self, path):
+ self.path = path
+
+ def get_type(self):
+ return TASK_MKDIR
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ return _adb_shell('mkdir -p %s' % self.path)
+
+class RmTask:
+ def __init__(self, path):
+ self.path = path
+
+ def get_type(self):
+ return TASK_RM
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ returncode, stdout, stderr = _adb_shell('ls %s' % self.path)
+ if returncode != 0 and stdout.endswith(': No such file or directory\n'):
+ return 0, "", ""
+ return _adb_shell('rm -r %s' % self.path)
+
+class IdmapPathTask:
+ def __init__(self, path_target_apk, path_overlay_apk, path_idmap):
+ self.path_target_apk = path_target_apk
+ self.path_overlay_apk = path_overlay_apk
+ self.path_idmap = path_idmap
+
+ def get_type(self):
+ return TASK_IDMAP_PATH
+
+ def get_name(self):
+ return self.path_idmap
+
+ def execute(self):
+ return _adb_shell('su system idmap --path "%s" "%s" "%s"' % (self.path_target_apk, self.path_overlay_apk, self.path_idmap))
+
+class IdmapScanTask:
+ def __init__(self, overlay_dir, target_pkg_name, target_pkg, idmap_dir, symlink_dir):
+ self.overlay_dir = overlay_dir
+ self.target_pkg_name = target_pkg_name
+ self.target_pkg = target_pkg
+ self.idmap_dir = idmap_dir
+ self.symlink_dir = symlink_dir
+
+ def get_type(self):
+ return TASK_IDMAP_SCAN
+
+ def get_name(self):
+ return self.target_pkg_name
+
+ def execute(self):
+ return _adb_shell('su system idmap --scan "%s" "%s" "%s" "%s"' % (self.overlay_dir, self.target_pkg_name, self.target_pkg, self.idmap_dir))
+
+class FileExistsTest:
+ def __init__(self, path):
+ self.path = path
+
+ def get_type(self):
+ return TASK_FILE_EXISTS_TEST
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ return _adb_shell('ls %s' % self.path)
+
+class GrepIdmapTest:
+ def __init__(self, path_idmap, pattern, expected_n):
+ self.path_idmap = path_idmap
+ self.pattern = pattern
+ self.expected_n = expected_n
+
+ def get_type(self):
+ return TASK_GREP_IDMAP_TEST
+
+ def get_name(self):
+ return self.pattern
+
+ def execute(self):
+ returncode, stdout, stderr = _adb_shell('idmap --inspect %s' % self.path_idmap)
+ if returncode != 0:
+ return returncode, stdout, stderr
+ all_matches = re.findall('\s' + self.pattern + '$', stdout, flags=re.MULTILINE)
+ if len(all_matches) != self.expected_n:
+ return 1, 'pattern=%s idmap=%s expected=%d found=%d\n' % (self.pattern, self.path_idmap, self.expected_n, len(all_matches)), ''
+ return 0, "", ""
+
+class Md5Test:
+ def __init__(self, path, expected_content):
+ self.path = path
+ self.expected_md5 = hashlib.md5(expected_content).hexdigest()
+
+ def get_type(self):
+ return TASK_MD5_TEST
+
+ def get_name(self):
+ return self.path
+
+ def execute(self):
+ returncode, stdout, stderr = _adb_shell('md5 %s' % self.path)
+ if returncode != 0:
+ return returncode, stdout, stderr
+ actual_md5 = stdout.split()[0]
+ if actual_md5 != self.expected_md5:
+ return 1, 'expected %s, got %s\n' % (self.expected_md5, actual_md5), ''
+ return 0, "", ""
+
+class StartTask:
+ def get_type(self):
+ return TASK_START
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ (returncode, stdout, stderr) = _adb_shell('start')
+ if returncode != 0:
+ return returncode, stdout, stderr
+
+ while True:
+ (returncode, stdout, stderr) = _adb_shell('getprop dev.bootcomplete')
+ if returncode != 0:
+ return returncode, stdout, stderr
+ if stdout.strip() == "1":
+ break
+ time.sleep(0.5)
+
+ return 0, "", ""
+
+class StopTask:
+ def get_type(self):
+ return TASK_STOP
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ (returncode, stdout, stderr) = _adb_shell('stop')
+ if returncode != 0:
+ return returncode, stdout, stderr
+ return _adb_shell('setprop dev.bootcomplete 0')
+
+class RootTask:
+ def get_type(self):
+ return TASK_ROOT
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ (returncode, stdout, stderr) = _adb_shell('getprop service.adb.root 0')
+ if returncode != 0:
+ return returncode, stdout, stderr
+ if stdout.strip() == '1': # already root
+ return 0, "", ""
+
+ argv = shlex.split(adb + ' root')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ if proc.returncode != 0:
+ return proc.returncode, stdout, stderr
+
+ argv = shlex.split(adb + ' wait-for-device')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ return proc.returncode, stdout, stderr
+
+class RemountTask:
+ def get_type(self):
+ return TASK_REMOUNT
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ argv = shlex.split(adb + ' remount')
+ proc = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ (stdout, stderr) = proc.communicate()
+ # adb remount returns 0 even if the operation failed, so check stdout
+ if stdout.startswith('remount failed:'):
+ return 1, stdout, stderr
+ return proc.returncode, stdout, stderr
+
+class CompoundTask:
+ def __init__(self, type, tasks):
+ self.type = type
+ self.tasks = tasks
+
+ def get_type(self):
+ return self.type
+
+ def get_name(self):
+ return ""
+
+ def execute(self):
+ for t in self.tasks:
+ (returncode, stdout, stderr) = t.execute()
+ if returncode != 0:
+ return returncode, stdout, stderr
+ return 0, "", ""
+
+def _create_disable_overlays_task():
+ tasks = [
+ RmTask("/vendor/overlay/framework_a.apk"),
+ RmTask("/vendor/overlay/framework_b.apk"),
+ RmTask("/data/resource-cache/vendor@overlay@framework_a.apk@idmap"),
+ RmTask("/data/resource-cache/vendor@overlay@framework_b.apk@idmap"),
+ RmTask("/vendor/overlay/app_a.apk"),
+ RmTask("/vendor/overlay/app_b.apk"),
+ RmTask("/data/resource-cache/vendor@overlay@app_a.apk@idmap"),
+ RmTask("/data/resource-cache/vendor@overlay@app_b.apk@idmap"),
+ ]
+ return CompoundTask(TASK_DISABLE_OVERLAYS, tasks)
+
+def _create_enable_single_overlay_task():
+ tasks = [
+ _create_disable_overlays_task(),
+ MkdirTask('/system/vendor'),
+ MkdirTask('/vendor/overlay'),
+ PushTask('/data/app/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_a.apk'),
+ PushTask('/data/app/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
+ ]
+ return CompoundTask(TASK_ENABLE_SINGLE_OVERLAY, tasks)
+
+def _create_enable_multiple_overlays_task():
+ tasks = [
+ _create_disable_overlays_task(),
+ MkdirTask('/system/vendor'),
+ MkdirTask('/vendor/overlay'),
+
+ PushTask('/data/app/com.android.overlaytest.overlay.apk', '/vendor/overlay/framework_b.apk'),
+ PushTask('/data/app/com.android.overlaytest.first_app_overlay.apk', '/vendor/overlay/app_a.apk'),
+ PushTask('/data/app/com.android.overlaytest.second_app_overlay.apk', '/vendor/overlay/app_b.apk'),
+ ]
+ return CompoundTask(TASK_ENABLE_MULTIPLE_OVERLAYS, tasks)
+
+def _create_setup_idmap_path_task(idmaps, symlinks):
+ tasks = [
+ _create_enable_single_overlay_task(),
+ RmTask(symlinks),
+ RmTask(idmaps),
+ MkdirTask(idmaps),
+ MkdirTask(symlinks),
+ ]
+ return CompoundTask(TASK_SETUP_IDMAP_PATH, tasks)
+
+def _create_setup_idmap_scan_task(idmaps, symlinks):
+ tasks = [
+ _create_enable_single_overlay_task(),
+ RmTask(symlinks),
+ RmTask(idmaps),
+ MkdirTask(idmaps),
+ MkdirTask(symlinks),
+ _create_enable_multiple_overlays_task(),
+ ]
+ return CompoundTask(TASK_SETUP_IDMAP_SCAN, tasks)
+
+def _handle_instrumentation_task_output(stdout, printer):
+ regex_status_code = re.compile(r'^INSTRUMENTATION_STATUS_CODE: -?(\d+)')
+ regex_name = re.compile(r'^INSTRUMENTATION_STATUS: test=(.*)')
+ regex_begin_stack = re.compile(r'^INSTRUMENTATION_STATUS: stack=(.*)')
+ regex_end_stack = re.compile(r'^$')
+
+ failed_tests = 0
+ current_test = None
+ current_stack = []
+ mode_stack = False
+ for line in stdout.split("\n"):
+ line = line.rstrip() # strip \r from adb output
+ m = regex_status_code.match(line)
+ if m:
+ c = int(m.group(1))
+ if c == 1:
+ printer.begin(TASK_INSTRUMENTATION_TEST, current_test)
+ elif c == 0:
+ printer.end_pass(TASK_INSTRUMENTATION_TEST, current_test)
+ else:
+ failed_tests += 1
+ current_stack.append("\n")
+ msg = "\n".join(current_stack)
+ printer.end_fail(TASK_INSTRUMENTATION_TEST, current_test, msg.rstrip() + '\n')
+ continue
+
+ m = regex_name.match(line)
+ if m:
+ current_test = m.group(1)
+ continue
+
+ m = regex_begin_stack.match(line)
+ if m:
+ mode_stack = True
+ current_stack = []
+ current_stack.append(" " + m.group(1))
+ continue
+
+ m = regex_end_stack.match(line)
+ if m:
+ mode_stack = False
+ continue
+
+ if mode_stack:
+ current_stack.append(" " + line.strip())
+
+ return failed_tests
+
+def _set_adb_device(option, opt, value, parser):
+ global adb
+ if opt == '-d' or opt == '--device':
+ adb = 'adb -d'
+ if opt == '-e' or opt == '--emulator':
+ adb = 'adb -e'
+ if opt == '-s' or opt == '--serial':
+ adb = 'adb -s ' + value
+
+def _create_opt_parser():
+ parser = optparse.OptionParser()
+ parser.add_option('-d', '--device', action='callback', callback=_set_adb_device,
+ help='pass -d to adb')
+ parser.add_option('-e', '--emulator', action='callback', callback=_set_adb_device,
+ help='pass -e to adb')
+ parser.add_option('-s', '--serial', type="str", action='callback', callback=_set_adb_device,
+ help='pass -s <serical> to adb')
+ parser.add_option('-C', '--no-color', action='store_false',
+ dest='use_color', default=True,
+ help='disable color escape sequences in output')
+ parser.add_option('-q', '--quiet', action='store_true',
+ dest='quiet_mode', default=False,
+ help='quiet mode, output only results')
+ parser.add_option('-b', '--no-build', action='store_false',
+ dest='do_build', default=True,
+ help='do not rebuild test projects')
+ parser.add_option('-k', '--continue', action='store_true',
+ dest='do_continue', default=False,
+ help='do not rebuild test projects')
+ parser.add_option('-i', '--test-idmap', action='store_true',
+ dest='test_idmap', default=False,
+ help='run tests for single overlay')
+ parser.add_option('-0', '--test-no-overlay', action='store_true',
+ dest='test_no_overlay', default=False,
+ help='run tests without any overlay')
+ parser.add_option('-1', '--test-single-overlay', action='store_true',
+ dest='test_single_overlay', default=False,
+ help='run tests for single overlay')
+ parser.add_option('-2', '--test-multiple-overlays', action='store_true',
+ dest='test_multiple_overlays', default=False,
+ help='run tests for multiple overlays')
+ return parser
+
+if __name__ == '__main__':
+ opt_parser = _create_opt_parser()
+ opts, args = opt_parser.parse_args(sys.argv[1:])
+ if not opts.test_idmap and not opts.test_no_overlay and not opts.test_single_overlay and not opts.test_multiple_overlays:
+ opts.test_idmap = True
+ opts.test_no_overlay = True
+ opts.test_single_overlay = True
+ opts.test_multiple_overlays = True
+ if len(args) > 0:
+ opt_parser.error("unexpected arguments: %s" % " ".join(args))
+ # will never reach this: opt_parser.error will call sys.exit
+
+ if opts.quiet_mode:
+ printer = QuietPrinter()
+ else:
+ printer = VerbosePrinter(opts.use_color)
+ tasks = []
+
+ # must be in the same directory as this script for compilation tasks to work
+ script = sys.argv[0]
+ dirname = os.path.dirname(script)
+ wd = os.path.realpath(dirname)
+ os.chdir(wd)
+
+ # build test cases
+ if opts.do_build:
+ tasks.append(CompilationTask('OverlayTest/Android.mk'))
+ tasks.append(CompilationTask('OverlayTestOverlay/Android.mk'))
+ tasks.append(CompilationTask('OverlayAppFirst/Android.mk'))
+ tasks.append(CompilationTask('OverlayAppSecond/Android.mk'))
+
+ # remount filesystem, install test project
+ tasks.append(RootTask())
+ tasks.append(RemountTask())
+ tasks.append(PushTask('/system/app/OverlayTest.apk', '/system/app/OverlayTest.apk'))
+
+ # test idmap
+ if opts.test_idmap:
+ idmaps='/data/local/tmp/idmaps'
+ symlinks='/data/local/tmp/symlinks'
+
+ # idmap --path
+ tasks.append(StopTask())
+ tasks.append(_create_setup_idmap_path_task(idmaps, symlinks))
+ tasks.append(StartTask())
+ tasks.append(IdmapPathTask('/vendor/overlay/framework_a.apk', '/system/framework/framework-res.apk', idmaps + '/a.idmap'))
+ tasks.append(FileExistsTest(idmaps + '/a.idmap'))
+ tasks.append(GrepIdmapTest(idmaps + '/a.idmap', 'bool/config_annoy_dianne', 1))
+
+ # idmap --scan
+ idmap = idmaps + '/vendor@overlay@framework_b.apk@idmap'
+ tasks.append(StopTask())
+ tasks.append(_create_setup_idmap_scan_task(idmaps, symlinks))
+ tasks.append(StartTask())
+ tasks.append(IdmapScanTask('/vendor/overlay', 'android', '/system/framework/framework-res.apk', idmaps, symlinks))
+ tasks.append(FileExistsTest(idmap))
+ tasks.append(GrepIdmapTest(idmap, 'bool/config_annoy_dianne', 1))
+
+ # overlays.list
+ overlays_list_path = '/data/resource-cache/overlays.list'
+ expected_content = '''\
+/vendor/overlay/framework_b.apk /data/resource-cache/vendor@overlay@framework_b.apk@idmap
+'''
+ tasks.append(FileExistsTest(overlays_list_path))
+ tasks.append(Md5Test(overlays_list_path, expected_content))
+
+ # idmap cleanup
+ tasks.append(RmTask(symlinks))
+ tasks.append(RmTask(idmaps))
+
+ # test no overlay
+ if opts.test_no_overlay:
+ tasks.append(StopTask())
+ tasks.append(_create_disable_overlays_task())
+ tasks.append(StartTask())
+ tasks.append(InstrumentationTask('com.android.overlaytest.WithoutOverlayTest'))
+
+ # test single overlay
+ if opts.test_single_overlay:
+ tasks.append(StopTask())
+ tasks.append(_create_enable_single_overlay_task())
+ tasks.append(StartTask())
+ tasks.append(InstrumentationTask('com.android.overlaytest.WithOverlayTest'))
+
+ # test multiple overlays
+ if opts.test_multiple_overlays:
+ tasks.append(StopTask())
+ tasks.append(_create_enable_multiple_overlays_task())
+ tasks.append(StartTask())
+ tasks.append(InstrumentationTask('com.android.overlaytest.WithMultipleOverlaysTest'))
+
+ ignored_errors = 0
+ for t in tasks:
+ type = t.get_type()
+ name = t.get_name()
+ if type == TASK_INSTRUMENTATION:
+ # InstrumentationTask will run several tests, but we want it
+ # to appear as if each test was run individually. Calling
+ # "am instrument" with a single test method is prohibitively
+ # expensive, so let's instead post-process the output to
+ # emulate individual calls.
+ retcode, stdout, stderr = t.execute()
+ if retcode != 0:
+ printer.begin(TASK_INSTRUMENTATION, name)
+ printer.end_fail(TASK_INSTRUMENTATION, name, stderr)
+ sys.exit(retcode)
+ retcode = _handle_instrumentation_task_output(stdout, printer)
+ if retcode != 0:
+ if not opts.do_continue:
+ sys.exit(retcode)
+ else:
+ ignored_errors += retcode
+ else:
+ printer.begin(type, name)
+ retcode, stdout, stderr = t.execute()
+ if retcode == 0:
+ printer.end_pass(type, name)
+ if retcode != 0:
+ if len(stderr) == 0:
+ # hope for output from stdout instead (true for eg adb shell rm)
+ stderr = stdout
+ printer.end_fail(type, name, stderr)
+ if not opts.do_continue:
+ sys.exit(retcode)
+ else:
+ ignored_errors += retcode
+ sys.exit(ignored_errors)
diff --git a/data/keyboards/Generic.kcm b/data/keyboards/Generic.kcm
index 695a74f..01d22ee 100644
--- a/data/keyboards/Generic.kcm
+++ b/data/keyboards/Generic.kcm
@@ -477,4 +477,128 @@
ctrl: fallback MENU
}
-### Gamepad buttons are handled by the view root ###
+### Gamepad buttons ###
+
+key BUTTON_A {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_B {
+ base: fallback BACK
+}
+
+key BUTTON_C {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_X {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_Y {
+ base: fallback BACK
+}
+
+key BUTTON_Z {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_L1 {
+ base: none
+}
+
+key BUTTON_R1 {
+ base: none
+}
+
+key BUTTON_L2 {
+ base: none
+}
+
+key BUTTON_R2 {
+ base: none
+}
+
+key BUTTON_THUMBL {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_THUMBR {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_START {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_SELECT {
+ base: fallback MENU
+}
+
+key BUTTON_MODE {
+ base: fallback MENU
+}
+
+key BUTTON_1 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_2 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_3 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_4 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_5 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_6 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_7 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_8 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_9 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_10 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_11 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_12 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_13 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_14 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_15 {
+ base: fallback DPAD_CENTER
+}
+
+key BUTTON_16 {
+ base: fallback DPAD_CENTER
+}
diff --git a/docs/html/design/building-blocks/buttons.jd b/docs/html/design/building-blocks/buttons.jd
index 2a77e24..3a34601 100644
--- a/docs/html/design/building-blocks/buttons.jd
+++ b/docs/html/design/building-blocks/buttons.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>A button consists of text and/or an image that clearly communicates what action
+<p itemprop="description">A button consists of text and/or an image that clearly communicates what action
will occur when the user touches it. A button can have an image, text, or both.
</p>
diff --git a/docs/html/design/building-blocks/dialogs.jd b/docs/html/design/building-blocks/dialogs.jd
index f9897f4..53d99b8 100644
--- a/docs/html/design/building-blocks/dialogs.jd
+++ b/docs/html/design/building-blocks/dialogs.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Dialogs prompt the user for decisions or additional information required by the app to continue a
+<p itemprop="description">Dialogs prompt the user for decisions or additional information required by the app to continue a
task. Such requests can range from simple Cancel/OK decisions to more complex layouts asking the
user to adjust settings or enter text.</p>
diff --git a/docs/html/design/building-blocks/grid-lists.jd b/docs/html/design/building-blocks/grid-lists.jd
index cef7514..d98637cc 100644
--- a/docs/html/design/building-blocks/grid-lists.jd
+++ b/docs/html/design/building-blocks/grid-lists.jd
@@ -11,7 +11,7 @@
</div>
</a>
-<p>Grid lists are an alternative to standard list views. They are best suited for showing data sets
+<p itemprop="description">Grid lists are an alternative to standard list views. They are best suited for showing data sets
that represent themselves through images. In contrast to simple lists, grid lists may scroll either
vertically or horizontally.</p>
diff --git a/docs/html/design/building-blocks/index.jd b/docs/html/design/building-blocks/index.jd
index e554775..7fb0e55 100644
--- a/docs/html/design/building-blocks/index.jd
+++ b/docs/html/design/building-blocks/index.jd
@@ -18,7 +18,8 @@
<div id="landing-graphic-container">
<div id="text-overlay">
- Your inventory of ready-to-use elements for creating outstanding apps.
+ <span itemprop="description">Your inventory of ready-to-use elements for creating
+ outstanding apps.</span>
<br><br>
<a href="{@docRoot}design/building-blocks/tabs.html" class="landing-page-link">Tabs</a>
</div>
diff --git a/docs/html/design/building-blocks/lists.jd b/docs/html/design/building-blocks/lists.jd
index 54fa442..4949d00 100644
--- a/docs/html/design/building-blocks/lists.jd
+++ b/docs/html/design/building-blocks/lists.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Lists present multiple line items in a vertical arrangement. They can be used for data selection as
+<p itemprop="description">Lists present multiple line items in a vertical arrangement. They can be used for data selection as
well as drilldown navigation.</p>
<div class="vspace size-1"> </div>
diff --git a/docs/html/design/building-blocks/pickers.jd b/docs/html/design/building-blocks/pickers.jd
index 860a126..fb5e287 100644
--- a/docs/html/design/building-blocks/pickers.jd
+++ b/docs/html/design/building-blocks/pickers.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Pickers provide a simple way to select a single value from a set. In addition to touching the
+<p itemprop="description">Pickers provide a simple way to select a single value from a set. In addition to touching the
up/down arrow buttons, it's possible to set the desired value from the keyboard or via a swipe
gesture.</p>
diff --git a/docs/html/design/building-blocks/spinners.jd b/docs/html/design/building-blocks/spinners.jd
index f8d92d4..f7d80e7 100644
--- a/docs/html/design/building-blocks/spinners.jd
+++ b/docs/html/design/building-blocks/spinners.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Spinners provide a quick way to select one value from a set. In the default state, a spinner shows
+<p itemprop="description">Spinners provide a quick way to select one value from a set. In the default state, a spinner shows
its currently selected value. Touching the spinner displays a dropdown menu with all other available
values, from which the user can select a new one.</p>
diff --git a/docs/html/design/building-blocks/switches.jd b/docs/html/design/building-blocks/switches.jd
index b294689..d435657 100644
--- a/docs/html/design/building-blocks/switches.jd
+++ b/docs/html/design/building-blocks/switches.jd
@@ -16,7 +16,7 @@
</div>
</a>
-<p>Checkboxes allow the user to select multiple options from a set. Avoid using a single checkbox to
+<p itemprop="description">Checkboxes allow the user to select multiple options from a set. Avoid using a single checkbox to
turn an option off or on. Instead, use an on/off switch.</p>
<img src="{@docRoot}design/media/switches_checkboxes.png">
diff --git a/docs/html/design/building-blocks/tabs.jd b/docs/html/design/building-blocks/tabs.jd
index 1fa3461..93818c3 100644
--- a/docs/html/design/building-blocks/tabs.jd
+++ b/docs/html/design/building-blocks/tabs.jd
@@ -11,7 +11,7 @@
</div>
</a>
-<p>Tabs in the action bar make it easy to explore and switch between different views or functional
+<p itemprop="description">Tabs in the action bar make it easy to explore and switch between different views or functional
aspects of your app, or to browse categorized data sets.</p>
<p>For details on using gestures to move between tabs, see the <a href="{@docRoot}design/patterns/swipe-views.html">Swipe Views</a> pattern.</p>
diff --git a/docs/html/design/building-blocks/text-fields.jd b/docs/html/design/building-blocks/text-fields.jd
index 4545bfb..e109d5f 100644
--- a/docs/html/design/building-blocks/text-fields.jd
+++ b/docs/html/design/building-blocks/text-fields.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Text fields allow the user to type text into your app. They can be either single line or multi-line.
+<p itemprop="description">Text fields allow the user to type text into your app. They can be either single line or multi-line.
Touching a text field places the cursor and automatically displays the keyboard. In addition to
typing, text fields allow for a variety of other activities, such as text selection (cut, copy,
paste) and data lookup via auto-completion.</p>
diff --git a/docs/html/design/get-started/creative-vision.jd b/docs/html/design/get-started/creative-vision.jd
index c57b185..1ce305a 100644
--- a/docs/html/design/get-started/creative-vision.jd
+++ b/docs/html/design/get-started/creative-vision.jd
@@ -5,7 +5,12 @@
<div class="vspace size-1"> </div>
-<p>We focused the design of Android around three overarching goals, which apply to our core apps as well as the system at large. As you design apps to work with Android, consider these goals:</p>
+<p itemprop="description">
+ We focused the design of Android around three overarching goals, which apply
+ to our core apps as well as the system at large. As you design apps to work
+ with Android, consider these goals: <em>Enchant me</em>, <em>Simplify my
+ life</em>, and <em>Make me amazing</em>
+</p>
<div class="vspace size-1"> </div>
diff --git a/docs/html/design/index.jd b/docs/html/design/index.jd
index 8f73d9c..9ba32dd 100644
--- a/docs/html/design/index.jd
+++ b/docs/html/design/index.jd
@@ -22,7 +22,8 @@
<div id="landing-graphic-container">
<div id="text-overlay">
- Welcome to <strong>Android Design</strong>, your place for learning how to design exceptional Android apps.
+ <span itemprop="description">Welcome to <strong>Android Design</strong>, your place for
+ learning how to design exceptional Android apps.</span>
<br><br>
Want to know what <strong>Android 4.4 KitKat</strong> has for designers? See <a href="{@docRoot}design/patterns/new.html">New in Android</a>.<br><br>
<a href="/design/get-started/creative-vision.html" class="landing-page-link">Creative Vision</a>
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
index 50c82fe..aaa6f16 100644
--- a/docs/html/design/patterns/accessibility.jd
+++ b/docs/html/design/patterns/accessibility.jd
@@ -1,5 +1,6 @@
page.title=Accessibility
-page.tags=accessibility,navigation,input
+page.tags="accessibility","navigation","input"
+page.metaDescription=Design an app that's universally accessible to people with visual impairment, color deficiency, hearing loss, and limited dexterity.
@jd:body
<a class="notice-developers" href="{@docRoot}training/accessibility/index.html">
@@ -86,4 +87,4 @@
<li>Provide alternatives to affordances that time out</li>
<li>Use standard framework controls or enable TalkBack for custom controls</li>
<li>Try it out yourself</li>
-</ul>
+</ul>
\ No newline at end of file
diff --git a/docs/html/design/patterns/actionbar.jd b/docs/html/design/patterns/actionbar.jd
index f0104b5..a1adbd3 100644
--- a/docs/html/design/patterns/actionbar.jd
+++ b/docs/html/design/patterns/actionbar.jd
@@ -1,5 +1,6 @@
page.title=Action Bar
-page.tags=actionbar,navigation
+page.tags="actionbar","navigation"
+page.metaDescription=The Action bar is an essential design element for all apps. Learn about what the action bar can do and how to use it in your apps.
@jd:body
<img src="{@docRoot}design/media/action_bar_pattern_overview.png">
@@ -277,4 +278,4 @@
<p>Sometimes it is important to display contextual information for your app that's always visible.
Examples are the number of unread messages in a messaging inbox view or the Now Playing information
in a music player. Carefully plan which important information you would like to display and
-structure your action bars accordingly.</p>
+structure your action bars accordingly.</p>
\ No newline at end of file
diff --git a/docs/html/design/patterns/compatibility.jd b/docs/html/design/patterns/compatibility.jd
index 5a1562c..dfc52c0 100644
--- a/docs/html/design/patterns/compatibility.jd
+++ b/docs/html/design/patterns/compatibility.jd
@@ -1,5 +1,6 @@
page.title=Backwards Compatibility
-page.tags=support
+page.tags="support"
+page.metaDescription=Notes on how Android 4.x adapts UI designed for older hardware and OS versions.
@jd:body
<a class="notice-developers" href="{@docRoot}training/basics/supporting-devices/index.html">
diff --git a/docs/html/design/patterns/help.jd b/docs/html/design/patterns/help.jd
index bf708b1..97949e2 100644
--- a/docs/html/design/patterns/help.jd
+++ b/docs/html/design/patterns/help.jd
@@ -6,7 +6,7 @@
<p>Some of your users will run into questions or problems along the way. They'll be looking for answers <strong>within your app</strong>, and if they don't find them quickly, they may leave and never come back.</p>
-<p>This page covers design patterns for making help accessible in your app and tips for creating help content for users who are eager for assistance.</p>
+<p itemprop="description">This page covers design patterns for making help accessible in your app and tips for creating help content for users who are eager for assistance.</p>
<h2 id="your-app">Designing Help into Your App</h2>
diff --git a/docs/html/design/patterns/index.jd b/docs/html/design/patterns/index.jd
index 4416de1..e091a29 100644
--- a/docs/html/design/patterns/index.jd
+++ b/docs/html/design/patterns/index.jd
@@ -18,7 +18,8 @@
<div id="landing-graphic-container">
<div id="text-overlay">
- Design apps that behave in a consistent, predictable fashion.
+ <span itemprop="description">Design apps that behave in a consistent, predictable
+ fashion.</span>
<br><br>
<a href="{@docRoot}design/patterns/new.html" class="landing-page-link">New in Android</a>
</div>
diff --git a/docs/html/design/patterns/multi-pane-layouts.jd b/docs/html/design/patterns/multi-pane-layouts.jd
index ff2dd4e..c207006 100644
--- a/docs/html/design/patterns/multi-pane-layouts.jd
+++ b/docs/html/design/patterns/multi-pane-layouts.jd
@@ -1,5 +1,6 @@
page.title=Multi-pane Layouts
-page.tags=tablet,navigation,layout,fragment
+page.tags="tablet","navigation","layout","fragment"
+page.metaDescription=Android devices come in many different screen sizes and types. Multi-pane layouts help you provide a balanced and aesthetically pleasing layout across the range of Android devices.
@jd:body
@@ -10,9 +11,11 @@
</div>
</a>
-<p>When writing an app for Android, keep in mind that Android devices come in many different screen
-sizes and types. Make sure that your app consistently provides a balanced and aesthetically pleasing
-layout by adjusting its content to varying screen sizes and orientations.</p>
+<p>When writing an app for Android, keep in mind that Android devices
+come in many different screen sizes and types. Make sure that your app consistently provides a
+balanced and aesthetically pleasing layout by adjusting its content to varying screen sizes and
+orientations.</p>
+
<p><em>Panels</em> are a great way for your app to achieve this. They allow you to combine multiple views into
one compound view when a lot of horizontal screen real estate is available and by splitting them up
when less space is available.</p>
diff --git a/docs/html/design/patterns/navigation.jd b/docs/html/design/patterns/navigation.jd
index 08828e8..3edf6ba 100644
--- a/docs/html/design/patterns/navigation.jd
+++ b/docs/html/design/patterns/navigation.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Consistent navigation is an essential component of the overall user experience. Few things frustrate
+<p itemprop="description">Consistent navigation is an essential component of the overall user experience. Few things frustrate
users more than basic navigation that behaves in inconsistent and unexpected ways. Android 3.0
introduced significant changes to the global navigation behavior. Thoughtfully following the
guidelines for Back and Up will make your app's navigation predictable and reliable for your users.</p>
diff --git a/docs/html/design/patterns/notifications.jd b/docs/html/design/patterns/notifications.jd
index 80f1b0e..41f9190 100644
--- a/docs/html/design/patterns/notifications.jd
+++ b/docs/html/design/patterns/notifications.jd
@@ -8,7 +8,7 @@
</div>
</a>
-<p>The notification system allows your app to keep the user informed about events, such as new chat messages or a calendar event. Think of notifications as a news channel that alerts the user to important events as they happen or a log that chronicles events while the user is not paying attention.</p>
+<p itemprop="description">The notification system allows your app to keep the user informed about events, such as new chat messages or a calendar event. Think of notifications as a news channel that alerts the user to important events as they happen or a log that chronicles events while the user is not paying attention.</p>
<h4>New in Jelly Bean</h4>
<p>In Jelly Bean, notifications received their most important structural and functional update since the beginning of Android.</p>
diff --git a/docs/html/design/patterns/selection.jd b/docs/html/design/patterns/selection.jd
index ee46795..be31677 100644
--- a/docs/html/design/patterns/selection.jd
+++ b/docs/html/design/patterns/selection.jd
@@ -35,9 +35,9 @@
</div>
</div>
-<h4>Using the contextual action bar (CAB)</h4>
-<p>The selection CAB is a temporary action bar that overlays your app's current action bar while data
-is selected. It appears after the user long presses on a selectable data item.</p>
+<h4>Using the contextual action bar</h4>
+<p itemprop="description">The contextual action bar (CAB) is a temporary action bar that overlays your app's current action bar while data
+is selected. It appears after the user long-presses on a selectable data item.</p>
<img src="{@docRoot}design/media/selection_cab_big.png">
diff --git a/docs/html/design/patterns/settings.jd b/docs/html/design/patterns/settings.jd
index a09193d..e3a3f05 100644
--- a/docs/html/design/patterns/settings.jd
+++ b/docs/html/design/patterns/settings.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Settings is a place in your app where users indicate their preferences for how your app should
+<p itemprop="description">Settings is a place in your app where users indicate their preferences for how your app should
behave. This benefits users because:</p>
<ul>
diff --git a/docs/html/design/patterns/swipe-views.jd b/docs/html/design/patterns/swipe-views.jd
index 89397ae..af5c9dc 100644
--- a/docs/html/design/patterns/swipe-views.jd
+++ b/docs/html/design/patterns/swipe-views.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Efficient navigation is one of the cornerstones of a well-designed app. While apps are generally
+<p itemprop="description">Efficient navigation is one of the cornerstones of a well-designed app. While apps are generally
built in a hierarchical fashion, there are instances where horizontal navigation can flatten
vertical hierarchies and make access to related data items faster and more enjoyable. Swipe views
allow the user to efficiently move from item to item using a simple gesture and thereby make
diff --git a/docs/html/design/patterns/widgets.jd b/docs/html/design/patterns/widgets.jd
index 953c125..654cf37 100644
--- a/docs/html/design/patterns/widgets.jd
+++ b/docs/html/design/patterns/widgets.jd
@@ -9,7 +9,7 @@
</div>
</a>
-<p>Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
+<p itemprop="description">Widgets are an essential aspect of home screen customization. You can imagine them as "at-a-glance" views of an app's most important data and functionality that is accessible right from the user's home screen. Users can move widgets across their home screen panels, and, if supported, resize them to tailor the amount of information within a widget to their preference.</p>
<h2>Widget types</h2>
<p>As you begin planning your widget, think about what kind of widget you're trying to build. Widgets typically fall into one of the following categories:</p>
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index 5dde600..d8d8c76 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -1,5 +1,7 @@
page.title=Iconography
-page.tags=icons
+page.tags="icons"
+meta.tags="icons, googleplay, listing, branding"
+page.titleFriendly=Guidelines for creating your app's icons
@jd:body
<img src="{@docRoot}design/media/iconography_overview.png">
diff --git a/docs/html/design/style/index.jd b/docs/html/design/style/index.jd
index 74d085b..f88fdb8 100644
--- a/docs/html/design/style/index.jd
+++ b/docs/html/design/style/index.jd
@@ -18,7 +18,8 @@
<div id="landing-graphic-container">
<div id="text-overlay">
- Build visually compelling apps that look great on any device.
+ <span itemprop="description">Build visually compelling apps that look great on any
+ device.</span>
<br><br>
<a href="{@docRoot}design/style/devices-displays.html" class="landing-page-link">Devices and Displays</a>
</div>
diff --git a/docs/html/distribute/googleplay/spotlight/index.jd b/docs/html/distribute/googleplay/spotlight/index.jd
index 6f92c78b..fc2e162 100644
--- a/docs/html/distribute/googleplay/spotlight/index.jd
+++ b/docs/html/distribute/googleplay/spotlight/index.jd
@@ -1,4 +1,7 @@
page.title=Spotlight
+page.tags="videos, google play, monetize, inapp"
+meta.tags="stories, googleplay, monetizing, landing"
+page.image=/images/video-kiwi.jpg
walkthru=0
header.hide=0
@@ -26,7 +29,7 @@
<div style="width:700px;">
<p style="margin-top:26px;
margin-bottom:12px;">
- Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has five of the top 25 grossing games on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
+ Android-first developer <a href="//play.google.com/store/apps/developer?id=Kiwi,+Inc." target="_android">Kiwi, Inc.</a> has had 5 titles in the top 25 grossing on Google Play, including <a href="https://play.google.com/store/apps/details?id=com.kiwi.shipwrecked" target="_android">Shipwrecked: Lost Island</a>, <a href="https://play.google.com/store/apps/details?id=com.kiwi.monsterpark" target="_android">Monsterama Park</a>, and <a href="https://play.google.com/store/apps/details?id=com.kiwi.mysteryestate" target="_android">Hidden Object: Mystery Estate</a>. Hear how Google Play helped them double revenue every six months with features like instant updates, staged rollouts, and more.</p>
</div>
<iframe style="float:left;
margin-right:24px;
diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd
index f09ef9f..506cf9d 100644
--- a/docs/html/guide/components/intents-common.jd
+++ b/docs/html/guide/components/intents-common.jd
@@ -880,13 +880,17 @@
(closest) zoom level is 23.
<p>Example: <code>"geo:47.6,-122.3?z=11"</code>
</dd>
- <dt><code>geo:0,0?q=lat,lng(label)</code></dt>
- <dd>Show the map at the given longitude and latitude with a string label.
- <p>Example: <code>"geo:0,0?q=34.99,-106.61(Treasure)"</code>
- </dd>
+ <dt><code>geo:0,0?q=lat,lng(label)</code></dt>
+ <dd>Show the map at the given longitude and latitude with a string label.
+ <p>Example: <code>"geo:0,0?q=34.99,-106.61(Treasure)"</code>
+ </dd>
<dt><code>geo:0,0?q=my+street+address</code></dt>
<dd>Show the location for "my street address" (may be a specific address or location query).
- <p>Example: <code>"geo:0,0?q=1600+amphitheatre+parkway+ca"</code>
+ <p>Example: <code>"geo:0,0?q=1600+Amphitheatre+Parkway%2C+CA"</code></p>
+ <p class="note"><strong>Note:</strong> All strings passed in the {@code geo} URI must
+ be encoded. For example, the string {@code 1st & Pike, Seattle} should become
+ {@code 1st%20%26%20Pike%2C%20Seattle}. Spaces in the string can be encoded with
+ {@code %20} or replaced with the plus sign ({@code +}).</p>
</dd>
</dl>
</dd>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 18b234e..73d5b74 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -367,6 +367,9 @@
<li><a href="<?cs var:toroot ?>guide/topics/media/mediaplayer.html">
<span class="en">Media Playback</span></a>
</li>
+ <li><a href="<?cs var:toroot ?>guide/topics/media/mediarouter.html">
+ <span class="en">MediaRouter</span></a>
+ </li>
<li><a href="<?cs var:toroot ?>guide/appendix/media-formats.html">
<span class="en">Supported Media Formats</span></a>
</li>
diff --git a/docs/html/guide/topics/manifest/action-element.jd b/docs/html/guide/topics/manifest/action-element.jd
index 037d0dc..54ee6ae 100644
--- a/docs/html/guide/topics/manifest/action-element.jd
+++ b/docs/html/guide/topics/manifest/action-element.jd
@@ -12,7 +12,7 @@
<p>
<dt>description:</dt>
-<dd>Adds an action to an intent filter.
+<dd itemprop="description">Adds an action to an intent filter.
An <code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code> element must contain
one or more {@code <action>} elements. If it doesn't contain any, no
Intent objects will get through the filter. See
diff --git a/docs/html/guide/topics/manifest/activity-alias-element.jd b/docs/html/guide/topics/manifest/activity-alias-element.jd
index d3df08b..343b02e 100644
--- a/docs/html/guide/topics/manifest/activity-alias-element.jd
+++ b/docs/html/guide/topics/manifest/activity-alias-element.jd
@@ -23,7 +23,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd>
<dt>description:</dt>
-<dd>An alias for an activity, named by the {@code targetActivity}
+<dd itemprop="description">An alias for an activity, named by the {@code targetActivity}
attribute. The target must be in the same application as the
alias and it must be declared before the alias in the manifest.
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index 8df1fdf..b648d48 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -54,7 +54,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd>
<dt>description:</dt>
-<dd>Declares an activity (an {@link android.app.Activity} subclass) that
+<dd itemprop="description">Declares an activity (an {@link android.app.Activity} subclass) that
implements part of the application's visual user interface. All activities
must be represented by {@code <activity>}
elements in the manifest file. Any that are not declared there will not be seen
@@ -580,7 +580,7 @@
<a href="#nm"><code>android:name</code></a> attribute.
<p>The system reads this attribute to determine which activity should be started when
- the use presses the Up button in the action bar. The system can also use this information to
+ the user presses the Up button in the action bar. The system can also use this information to
synthesize a back stack of activities with {@link android.app.TaskStackBuilder}.</p>
<p>To support API levels 4 - 16, you can also declare the parent activity with a {@code
diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd
index 46500aa..28deed9 100644
--- a/docs/html/guide/topics/manifest/application-element.jd
+++ b/docs/html/guide/topics/manifest/application-element.jd
@@ -47,7 +47,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/uses-library-element.html"><uses-library></a></code></dd>
<dt>description:</dt>
-<dd>The declaration of the application. This element contains subelements
+<dd itemprop="description">The declaration of the application. This element contains subelements
that declare each of the application's components and has attributes
that can affect all the components. Many of these attributes (such as
{@code icon}, {@code label}, {@code permission}, {@code process},
diff --git a/docs/html/guide/topics/manifest/category-element.jd b/docs/html/guide/topics/manifest/category-element.jd
index a4b93ee..563ed10 100644
--- a/docs/html/guide/topics/manifest/category-element.jd
+++ b/docs/html/guide/topics/manifest/category-element.jd
@@ -11,7 +11,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code></dd>
<dt>description:</dt>
-<dd>Adds a category name to an intent filter. See
+<dd itemprop="description">Adds a category name to an intent filter. See
<a href="{@docRoot}guide/components/intents-filters.html">Intents and
Intent Filters</a> for details on intent filters and the role of category
specifications within a filter.</dd>
diff --git a/docs/html/guide/topics/manifest/compatible-screens-element.jd b/docs/html/guide/topics/manifest/compatible-screens-element.jd
index 00cbfe5..3606b15 100644
--- a/docs/html/guide/topics/manifest/compatible-screens-element.jd
+++ b/docs/html/guide/topics/manifest/compatible-screens-element.jd
@@ -20,7 +20,7 @@
href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Specifies each screen configuration with which the application is compatible. Only one instance
+<dd itemprop="description">Specifies each screen configuration with which the application is compatible. Only one instance
of the {@code <compatible-screens>} element is allowed in the manifest, but it can
contain multiple <code><screen></code> elements. Each <code><screen></code> element
specifies a specific screen size-density combination with which the application is compatible.
diff --git a/docs/html/guide/topics/manifest/data-element.jd b/docs/html/guide/topics/manifest/data-element.jd
index 27950d0..ecba508 100644
--- a/docs/html/guide/topics/manifest/data-element.jd
+++ b/docs/html/guide/topics/manifest/data-element.jd
@@ -18,7 +18,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/intent-filter-element.html"><intent-filter></a></code></dd>
<dt>description:</dt>
-<dd>Adds a data specification to an intent filter. The specification can
+<dd itemprop="description">Adds a data specification to an intent filter. The specification can
be just a data type (the <code><a href="{@docRoot}guide/topics/manifest/data-element.html#mime">mimeType</a></code> attribute),
just a URI, or both a data type and a URI. A URI is specified by separate
attributes for each of its parts:
diff --git a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
index dc98cbb..2179359 100644
--- a/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
+++ b/docs/html/guide/topics/manifest/grant-uri-permission-element.jd
@@ -13,7 +13,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/provider-element.html"><provider></a></code></dd>
<dt>description:</dt>
-<dd>Specifies which data subsets of the parent content provider permission
+<dd itemprop="description">Specifies which data subsets of the parent content provider permission
can be granted for. Data subsets are indicated by the path part of a
{@code content:} URI. (The authority part of the URI identifies the
content provider.)
diff --git a/docs/html/guide/topics/manifest/instrumentation-element.jd b/docs/html/guide/topics/manifest/instrumentation-element.jd
index 9408b84..74be559 100644
--- a/docs/html/guide/topics/manifest/instrumentation-element.jd
+++ b/docs/html/guide/topics/manifest/instrumentation-element.jd
@@ -16,7 +16,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Declares an {@link android.app.Instrumentation} class that enables you
+<dd itemprop="description">Declares an {@link android.app.Instrumentation} class that enables you
to monitor an application's interaction with the system. The Instrumentation
object is instantiated before any of the application's components.</dd>
diff --git a/docs/html/guide/topics/manifest/intent-filter-element.jd b/docs/html/guide/topics/manifest/intent-filter-element.jd
index 68da981..14b4e03 100644
--- a/docs/html/guide/topics/manifest/intent-filter-element.jd
+++ b/docs/html/guide/topics/manifest/intent-filter-element.jd
@@ -25,7 +25,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/data-element.html"><data></a></code></dd>
<dt>description:</dt>
-<dd>Specifies the types of intents that an activity, service, or broadcast
+<dd itemprop="description">Specifies the types of intents that an activity, service, or broadcast
receiver can respond to. An intent filter declares the capabilities of its
parent component — what an activity or service can do and what types
of broadcasts a receiver can handle. It opens the component to receiving
diff --git a/docs/html/guide/topics/manifest/manifest-element.jd b/docs/html/guide/topics/manifest/manifest-element.jd
index 12690d2..20dc4ea 100644
--- a/docs/html/guide/topics/manifest/manifest-element.jd
+++ b/docs/html/guide/topics/manifest/manifest-element.jd
@@ -39,7 +39,7 @@
<p>
<dt>description:</dt>
-<dd>The root element of the AndroidManifest.xml file. It must
+<dd itemprop="description">The root element of the AndroidManifest.xml file. It must
contain an <code><a href="{@docRoot}guide/topics/manifest/application-element.html"><application></a></code> element
and specify {@code xmlns:android} and {@code package} attributes.</dd>
diff --git a/docs/html/guide/topics/manifest/manifest-intro.jd b/docs/html/guide/topics/manifest/manifest-intro.jd
index 76fe2a2..d2a9308 100644
--- a/docs/html/guide/topics/manifest/manifest-intro.jd
+++ b/docs/html/guide/topics/manifest/manifest-intro.jd
@@ -20,11 +20,11 @@
</div>
<p>
-Every application must have an AndroidManifest.xml file (with precisely that
-name) in its root directory. The manifest presents essential information about
-the application to the Android system, information the system must have before
-it can run any of the application's code. Among other things, the manifest
-does the following:
+ Every application must have an AndroidManifest.xml file (with precisely that
+ name) in its root directory. <span itemprop="description">The manifest file
+ presents essential information about your app to the Android system,
+ information the system must have before it can run any of the app's
+ code.</span> Among other things, the manifest does the following:
</p>
<ul>
diff --git a/docs/html/guide/topics/manifest/meta-data-element.jd b/docs/html/guide/topics/manifest/meta-data-element.jd
index ee80c84..241153b 100644
--- a/docs/html/guide/topics/manifest/meta-data-element.jd
+++ b/docs/html/guide/topics/manifest/meta-data-element.jd
@@ -18,7 +18,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/service-element.html"><service></a></code>
<dt>description:</dt>
-<dd>A name-value pair for an item of additional, arbitrary data that can
+<dd itemprop="description">A name-value pair for an item of additional, arbitrary data that can
be supplied to the parent component. A component element can contain any
number of {@code <meta-data>} subelements. The values from all of
them are collected in a single {@link android.os.Bundle} object and made
diff --git a/docs/html/guide/topics/manifest/path-permission-element.jd b/docs/html/guide/topics/manifest/path-permission-element.jd
index e644d68..cdaf82b 100644
--- a/docs/html/guide/topics/manifest/path-permission-element.jd
+++ b/docs/html/guide/topics/manifest/path-permission-element.jd
@@ -23,7 +23,7 @@
-->
<dt>description:</dt>
-<dd>Defines the path and required permissions for a specific subset of data
+<dd itemprop="description">Defines the path and required permissions for a specific subset of data
within a content provider. This element can be
specified multiple times to supply multiple paths.
diff --git a/docs/html/guide/topics/manifest/permission-element.jd b/docs/html/guide/topics/manifest/permission-element.jd
index a23fb4b..4bb5f6a 100644
--- a/docs/html/guide/topics/manifest/permission-element.jd
+++ b/docs/html/guide/topics/manifest/permission-element.jd
@@ -17,7 +17,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Declares a security permission that can be used to limit access
+<dd itemprop="description">Declares a security permission that can be used to limit access
to specific components or features of this or other applications.
See the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a>
section in the introduction,
diff --git a/docs/html/guide/topics/manifest/permission-group-element.jd b/docs/html/guide/topics/manifest/permission-group-element.jd
index fc1de1f..3221d4b 100644
--- a/docs/html/guide/topics/manifest/permission-group-element.jd
+++ b/docs/html/guide/topics/manifest/permission-group-element.jd
@@ -14,7 +14,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Declares a name for a logical grouping of related permissions. Individual
+<dd itemprop="description">Declares a name for a logical grouping of related permissions. Individual
permission join the group through the {@code permissionGroup} attribute of the
<code><a href="{@docRoot}guide/topics/manifest/permission-element.html"><permission></a></code> element. Members of a group are
presented together in the user interface.
diff --git a/docs/html/guide/topics/manifest/permission-tree-element.jd b/docs/html/guide/topics/manifest/permission-tree-element.jd
index a9c00cd..21d7352 100644
--- a/docs/html/guide/topics/manifest/permission-tree-element.jd
+++ b/docs/html/guide/topics/manifest/permission-tree-element.jd
@@ -13,7 +13,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Declares the base name for a tree of permissions. The application takes
+<dd itemprop="description">Declares the base name for a tree of permissions. The application takes
ownership of all names within the tree. It can dynamically add new permissions
to the tree by calling <code>{@link android.content.pm.PackageManager#addPermission PackageManager.addPermission()}</code>. Names within the tree are separated by
periods ('{@code .}'). For example, if the base name is
diff --git a/docs/html/guide/topics/manifest/provider-element.jd b/docs/html/guide/topics/manifest/provider-element.jd
index 6cf6843..f3ffd58 100644
--- a/docs/html/guide/topics/manifest/provider-element.jd
+++ b/docs/html/guide/topics/manifest/provider-element.jd
@@ -36,7 +36,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/path-permission-element.html"><path-permission></a></code></dd>
<dt>description:</dt>
-<dd>
+<dd itemprop="description">
Declares a content provider component. A content provider is a subclass of
{@link android.content.ContentProvider} that supplies structured access to data managed by the
application. All content providers in your application must be defined in a
diff --git a/docs/html/guide/topics/manifest/receiver-element.jd b/docs/html/guide/topics/manifest/receiver-element.jd
index 8416c0c..df2437e 100644
--- a/docs/html/guide/topics/manifest/receiver-element.jd
+++ b/docs/html/guide/topics/manifest/receiver-element.jd
@@ -23,7 +23,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd>
<dt>description:</dt>
-<dd>Declares a broadcast receiver (a {@link android.content.BroadcastReceiver}
+<dd itemprop="description">Declares a broadcast receiver (a {@link android.content.BroadcastReceiver}
subclass) as one of the application's components. Broadcast receivers enable
applications to receive intents that are broadcast by the system or by other
applications, even when other components of the application are not running.
diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd
index 14eed67..2213b72 100644
--- a/docs/html/guide/topics/manifest/service-element.jd
+++ b/docs/html/guide/topics/manifest/service-element.jd
@@ -24,7 +24,7 @@
<br/><code><a href="{@docRoot}guide/topics/manifest/meta-data-element.html"><meta-data></a></code></dd>
<dt>description:</dt>
-<dd>Declares a service (a {@link android.app.Service} subclass) as one
+<dd itemprop="description">Declares a service (a {@link android.app.Service} subclass) as one
of the application's components. Unlike activities, services lack a
visual user interface. They're used to implement long-running background
operations or a rich communications API that can be called by other
diff --git a/docs/html/guide/topics/manifest/supports-gl-texture-element.jd b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd
index fa39317..ab751c2 100644
--- a/docs/html/guide/topics/manifest/supports-gl-texture-element.jd
+++ b/docs/html/guide/topics/manifest/supports-gl-texture-element.jd
@@ -34,7 +34,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Declares a single GL texture compression format that is supported by
+<dd itemprop="description">Declares a single GL texture compression format that is supported by
the application.
<p>An application "supports" a GL texture compression format if it is capable of
diff --git a/docs/html/guide/topics/manifest/supports-screens-element.jd b/docs/html/guide/topics/manifest/supports-screens-element.jd
index ae14121..bbeceb7 100644
--- a/docs/html/guide/topics/manifest/supports-screens-element.jd
+++ b/docs/html/guide/topics/manifest/supports-screens-element.jd
@@ -24,7 +24,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Lets you specify the screen sizes your application supports and enable <a
+<dd itemprop="description">Lets you specify the screen sizes your application supports and enable <a
href="{@docRoot}guide/practices/screen-compat-mode.html">screen compatibility mode</a> for screens
larger than what your application supports. It's important that you always use this element in your
application to specify the screen sizes your application supports.
diff --git a/docs/html/guide/topics/manifest/uses-configuration-element.jd b/docs/html/guide/topics/manifest/uses-configuration-element.jd
index e9a0ba4..15fd49c1 100644
--- a/docs/html/guide/topics/manifest/uses-configuration-element.jd
+++ b/docs/html/guide/topics/manifest/uses-configuration-element.jd
@@ -27,7 +27,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Indicates what hardware and software features the application requires.
+<dd itemprop="description">Indicates what hardware and software features the application requires.
For example, an application might specify that it requires a physical keyboard
or a particular navigation device, like a trackball. The specification is
used to avoid installing the application on devices where it will not work.
diff --git a/docs/html/guide/topics/manifest/uses-feature-element.jd b/docs/html/guide/topics/manifest/uses-feature-element.jd
index 884eeb5..4057736c 100644
--- a/docs/html/guide/topics/manifest/uses-feature-element.jd
+++ b/docs/html/guide/topics/manifest/uses-feature-element.jd
@@ -62,7 +62,7 @@
href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Declares a single hardware or software feature that is used by the
+<dd itemprop="description">Declares a single hardware or software feature that is used by the
application.
<p>The purpose of a <code><uses-feature></code> declaration is to inform
@@ -549,11 +549,15 @@
</td>
</tr>
<tr>
- <td>Bluetooth</td>
- <td><code>android.hardware.bluetooth</td>
+ <td rowspan="2">Bluetooth</td>
+ <td><code>android.hardware.bluetooth</code></td>
<td>The application uses Bluetooth radio features in the device.</td>
- <td>If your app uses Bluetooth Low Energy, also declare
- {@code android.software.bluetooth_le}.</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td><code>android.hardware.bluetooth_le</code></td>
+ <td>The application uses Bluetooth Low Energy radio features in the device.</td>
+ <td></td>
</tr>
<tr>
<td rowspan="5">Camera</td>
@@ -586,6 +590,13 @@
</tr>
<tr>
+ <td>Infrared</td>
+ <td><code>android.hardware.consumerir</code></td>
+ <td>The application uses the consumer IR capabilities on the device.</td>
+ <td></td>
+</tr>
+
+<tr>
<td rowspan="3">Location</td>
<td><code>android.hardware.location</code></td>
<td>The application uses one or more features on the device for determining
@@ -613,13 +624,18 @@
<td></td>
</tr>
<tr>
- <td>NFC</td>
+ <td rowspan="2">NFC</td>
<td><code>android.hardware.nfc</td>
<td>The application uses Near Field Communications radio features in the device.</td>
<td></td>
</tr>
<tr>
- <td rowspan="6">Sensors</td>
+ <td><code>android.hardware.nfc.hce</code></td>
+ <td>The application uses the NFC card emulation feature in the device.</td>
+ <td></td>
+</tr>
+<tr>
+ <td rowspan="8">Sensors</td>
<td><code>android.hardware.sensor.accelerometer</code></td>
<td>The application uses motion readings from an accelerometer on the
device.</td>
@@ -651,6 +667,16 @@
<td>The application uses the device's proximity sensor.</td>
<td></td>
</tr>
+<tr>
+ <td><code>android.hardware.sensor.stepcounter</code></td>
+ <td>The application uses the device's step counter.</td>
+ <td></td>
+</tr>
+<tr>
+ <td><code>android.hardware.sensor.stepdetector</code></td>
+ <td>The application uses the device's step detector.</td>
+ <td></td>
+</tr>
<tr>
<td rowspan="2">Screen</td>
@@ -828,11 +854,15 @@
</tr>
<tr>
- <td>Wifi</td>
+ <td rowspan="2">Wi-Fi</td>
<td><code>android.hardware.wifi</code></td>
- <td>The application uses 802.11 networking (wifi) features on the device.</td>
+ <td>The application uses 802.11 networking (Wi-Fi) features on the device.</td>
<td></td>
</tr>
+<tr>
+ <td><code>android.hardware.wifi.direct</code></td>
+ <td>The application uses the Wi-Fi Direct networking features on the device.</td>
+</tr>
</table>
@@ -857,11 +887,9 @@
that include a Home screen or similar location where users can embed App Widgets.</td>
</tr>
<tr>
- <td>Bluetooth Low Energy</td>
- <td><code>android.software.bluetooth_le</code></td>
- <td><p>The application uses Bluetooth Low Energy APIs and should be installed only on devices
- that are capable of communicating with other devices via Bluetooth Low Energy.
- <p>This implicitly also declares the {@code android.hardware.bluetooth} feature.</td>
+ <td>Device Management</td>
+ <td><code>android.software.device_admin</code></td>
+ <td>The application uses device policy enforcement via device administrators.</td>
</tr>
<tr>
<td>Home Screen</td>
@@ -1056,7 +1084,7 @@
</tr>
<tr>
- <td rowspan="3">Wifi</td>
+ <td rowspan="3">Wi-Fi</td>
<td><code>ACCESS_WIFI_STATE</code></td>
<td><code>android.hardware.wifi</code></td>
<!-- <td></td> -->
diff --git a/docs/html/guide/topics/manifest/uses-library-element.jd b/docs/html/guide/topics/manifest/uses-library-element.jd
index 253807e..aa7ca82 100644
--- a/docs/html/guide/topics/manifest/uses-library-element.jd
+++ b/docs/html/guide/topics/manifest/uses-library-element.jd
@@ -31,7 +31,7 @@
</code>
</dd>
<dt>description:</dt>
-<dd>
+<dd itemprop="descridption">
Specifies a shared library that the application must be linked against.
This element tells the system to include the library's code in the class
loader for the package.
diff --git a/docs/html/guide/topics/manifest/uses-permission-element.jd b/docs/html/guide/topics/manifest/uses-permission-element.jd
index bd7091e..9394114 100644
--- a/docs/html/guide/topics/manifest/uses-permission-element.jd
+++ b/docs/html/guide/topics/manifest/uses-permission-element.jd
@@ -42,7 +42,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Requests a permission that the application must be granted in
+<dd itemprop="description">Requests a permission that the application must be granted in
order for it to operate correctly. Permissions are granted by the user when the
application is installed, not while it's running.
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index c88e6be..79a37f0 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -48,7 +48,7 @@
<dd><code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code></dd>
<dt>description:</dt>
-<dd>Lets you express an application's compatibility with one or more versions of the Android platform,
+<dd itemprop="description"><p> Lets you express an application's compatibility with one or more versions of the Android platform,
by means of an API Level integer. The API Level expressed by an application will be compared to the
API Level of a given Android system, which may vary among different Android devices.
</p>
diff --git a/docs/html/guide/topics/media/mediarouter.jd b/docs/html/guide/topics/media/mediarouter.jd
new file mode 100644
index 0000000..1b10265
--- /dev/null
+++ b/docs/html/guide/topics/media/mediarouter.jd
@@ -0,0 +1,670 @@
+page.title=MediaRouter
+page.tags="cast","chromecast","wireless display","miracast"
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#overview">Overview</a>
+ <ol>
+ <li><a href="#mr-packages">Media router packages</a></li>
+ </ol>
+ </li>
+ <li><a href="#cast-ui">Cast User Interface</a>
+ <ol>
+ <li><a href="#cast-button">Cast button</a></li>
+ <li><a href="#selector">Media route selector</a></li>
+ </ol>
+ </li>
+ <li><a href="#media-routes">Connecting to Media Routes</a>
+ <ol>
+ <li><a href="#create-mr-callback">Creating a MediaRouter callback</a></li>
+ <li><a href="#attach-mr-callback">Attaching a callback to MediaRouter</a></li>
+ </ol>
+ <li><a href="#remote-playback">Remote Playback</a></li>
+ <li><a href="#secondary-output">Secondary Output</a>
+ <ol>
+ <li><a href="#pres-obj">Creating a Presentation object</a></li>
+ <li><a href="#pres-cntrlr">Creating a Presentation controller</a></li>
+ </ol>
+ </li>
+ </ol>
+ <h2>Key Classes</h2>
+ <ol>
+ <li>{@link android.support.v7.media.MediaRouter}</li>
+ <li>{@link android.support.v7.media.MediaRouter.Callback}</li>
+ <li>{@link android.support.v7.media.MediaRouteProvider}</li>
+ </ol>
+ </div>
+</div>
+
+<p>As users connect their televisions, home theater systems and music players with wireless
+ technologies, they want to be able to play content from Android apps on these larger,
+ louder devices. Enabling this kind of playback can turn your one-device, one-user app
+ into a shared experience that delights and inspires multiple users.</p>
+
+<p>The Android media router APIs are designed to enable media display and playback on these
+ secondary devices. There are two main approaches you can use to play content using these
+ APIs:</p>
+
+<ul>
+ <li><strong>Remote Playback</strong> — This approach uses the receiving device to handle
+ the content data retrieval, decoding, and playback, while an Android device in the user's hand
+ is used as a remote control. This approach is used by Android apps that support
+ <a href="https://developers.google.com/cast/">Google Cast</a>.</li>
+ <li><strong>Secondary Output</strong> — With this approach, your app retrieves, renders
+ and streams video or music directly to the receiving device. This approach is used to support
+ Wireless Display output
+ on Android.</li>
+</ul>
+
+<p>This guide explains how your app can deliver media to secondary playback devices using either
+ of these approaches.</p>
+
+
+<h2 id="overview">Overview</h2>
+
+<p>The media router APIs enable a broad range of media output to playback equipment connected to
+ Android devices through wireless and wired means. To enable these connections,
+ the media router framework abstracts the logical paths for audio and video output for an Android
+ device. This architecture allows your app to quickly channel media content to
+ connected playback devices such as home theaters and sound systems that provide Android media
+ route support.</p>
+
+<p>In order to use this framework within your app, you must get an instance
+ of the {@link android.support.v7.media.MediaRouter} framework object and attach a {@link
+ android.support.v7.media.MediaRouter.Callback} object to listen for events in
+ available media routes. Content channelled through a media route passes through the route's
+ associated {@link android.support.v7.media.MediaRouteProvider} (except in a few special cases,
+ such as a Bluetooth output device). The following diagram provides a high-level view of the
+ classes your app can use to play content with the media router framework.
+</p>
+
+<img src="{@docRoot}images/mediarouter/mediarouter-framework.png" alt="" id="figure1"/>
+<p class="img-caption">
+ <strong>Figure 1.</strong> Overview of key media router classes used by apps.
+</p>
+
+<p>Manufacturers of media playback hardware that is not supported by the media router framework
+ can add support for their devices by implementing a
+ {@link android.support.v7.media.MediaRouteProvider} and distributing it as an application.
+ For more information on implementing a media route provider, see the {@link
+ android.support.v7.media.MediaRouteProvider} reference documentation and the v7-mediarouter
+ support library sample {@code <sdk>/extras/android/compatibility/v7/mediarouter}.
+</p>
+
+
+<h3 id="mr-packages">Media router packages</h3>
+
+<p>The media router APIs are provided as part of the Android Support Library version 18 and
+ higher, in the
+ <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter support
+ library</a>. Specifically, you should use the classes in the {@link android.support.v7.media}
+ package for media router functions. These APIs are compatible with devices running Android 2.1
+ (API level 7) and higher.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> There is another set of media router APIs provided in the
+ {@link android.media} that have been superseded by the v7-mediarouter support library.
+ You <em>should not</em> use the {@link android.media} classes for media router functions.
+</p>
+
+<p>In order to use the {@link android.support.v7.media} media router classes, you must add
+ the <a href="{@docRoot}tools/support-library/features.html#v7-mediarouter">v7-mediarouter
+ support library package</a> to your app development project.
+</p>
+
+
+<h2 id="cast-ui">Cast User Interface</h2>
+
+<p>
+ Android apps that implement the media router API should include a Cast button
+ as part of their user interface, to allow users to select a media route to play media on
+ a secondary output device. The media router framework provides a standard interface for
+ the button, which you should use to help users recognize and use the feature in your app.
+ Figure 2 illustrates how the Cast button should appear in an app.
+</p>
+
+<img src="{@docRoot}images/mediarouter/mediarouter-actionbar.png" alt="" width="428" id="figure2"/>
+<p class="img-caption">
+ <strong>Figure 2.</strong> A Cast button shown on the right side of the action bar.
+</p>
+
+<p class="caution">
+ <strong>Caution:</strong> When implementing an activity that provides a media router interface
+ you <em>must</em> extend either {@link android.support.v7.app.ActionBarActivity}
+ or {@link android.support.v4.app.FragmentActivity} from the Android Support Library, even if
+ your {@code android:minSdkVersion} is API 11 or higher.
+</p>
+
+
+<h3 id="cast-button">Cast button</h3>
+
+<p>The recommended way to implement the Cast button user interface is to extend your activity
+ from {@link android.support.v7.app.ActionBarActivity} and use the {@link
+ android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method to add an options menu.
+ The Cast button must use the {@link android.support.v7.app.MediaRouteActionProvider} class
+ as its action:</p>
+
+<pre>
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ >
+
+ <item android:id="@+id/media_route_menu_item"
+ android:title="@string/media_route_menu_title"
+ <strong>app:actionProviderClass="android.support.v7.app.MediaRouteActionProvider"</strong>
+ app:showAsAction="always"
+ />
+</menu>
+</pre>
+
+<p>For more information about implementing the action bar in your app,
+ see the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a>
+ developer guide.
+</p>
+
+<p>Once you have added the Cast button to your user interface, you must attach a media
+ route selector object. Building a selector is discussed in the next section.
+</p>
+
+<p>If you do not want a menu in your action bar, you can also add a Cast button to your app using
+ {@link android.support.v7.app.MediaRouteButton}. If you choose this approach, you should add
+ this button to your app's action bar according to the
+ <a href="https://developers.google.com/cast/docs/design_checklist">Google Cast Design
+ Checklist</a>. You must also attach a media route selector to the button using the
+ {@link android.support.v7.app.MediaRouteButton#setRouteSelector setRouteSelector()} method.
+</p>
+
+<p>For guidelines on incorporating the Cast button into your application, review the
+ <a href="https://developers.google.com/cast/docs/design_checklist">Google Cast Design
+ Checklist</a>.</p>
+
+
+<h3 id="selector">Media route selector</h3>
+
+<p>When a user presses the Cast button, the media router framework looks for available media
+ routes and presents a list of choices to the user, as shown in figure 3.</p>
+
+<img src="{@docRoot}images/mediarouter/mediarouter-selector-ui.png" alt="" width="500" id="figure3"/>
+<p class="img-caption">
+ <strong>Figure 3.</strong> A list of available media routes, shown after pressing the Cast button.
+</p>
+
+
+<p>The <em>types</em> of media routes that appear on this list—Remote Playback, Secondary
+ Output or others—are defined by your app.You define these type by creating a {@link
+ android.support.v7.media.MediaRouteSelector}, which accepts {@link
+ android.support.v7.media.MediaControlIntent} objects provided by the framework and other media
+ route providers created by you or other developers. The framework-provided route categories are as
+ follows:
+</p>
+
+<ul>
+ <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_AUDIO
+ CATEGORY_LIVE_AUDIO} — Output of audio to a secondary output device, such as a
+ wireless-enabled music system.</li>
+ <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_LIVE_VIDEO
+ CATEGORY_LIVE_VIDEO} — Output of video to a secondary output device, such as Wireless
+ Display devices.</li>
+ <li>{@link android.support.v7.media.MediaControlIntent#CATEGORY_REMOTE_PLAYBACK
+ CATEGORY_REMOTE_PLAYBACK} — Play video or audio on a separate device that supports the
+ <a href="https://developers.google.com/cast/">Google Cast</a> remote control protocol, such
+ as <a href="https://www.google.com/url?q=http://www.google.com/chromecast">Chromecast</a>.
+ </li>
+</ul>
+
+<p>When creating a {@link android.support.v7.media.MediaRouteSelector} object, use the
+ {@link android.support.v7.media.MediaRouteSelector.Builder} class to create the object and set
+ the media playback categories (control categories), as shown
+ in the following code sample:</p>
+
+<pre>
+public class MediaRouterPlaybackActivity extends ActionBarActivity {
+ private MediaRouteSelector mSelector;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Create a route selector for the type of routes your app supports.
+ <strong>mSelector = new MediaRouteSelector.Builder()
+ // These are the framework-supported intents
+ .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
+ .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
+ .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)</strong>
+ .build();
+ }
+}
+</pre>
+
+<p>The media router framework uses this selector object to provide an interface for selecting
+ media routes that your app supports, as shown in figure 3. Once you have defined this selector,
+ you attach it to the {@link android.support.v7.app.MediaRouteActionProvider} object associated
+ with the Cast menu item, as shown in the following code sample:</p>
+
+<pre>
+@Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ // Inflate the menu and configure the media router action provider.
+ getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);
+
+ // Attach the MediaRouteSelector to the menu item
+ MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
+ MediaRouteActionProvider mediaRouteActionProvider =
+ (MediaRouteActionProvider)MenuItemCompat.getActionProvider(
+ mediaRouteMenuItem);
+ <strong>mediaRouteActionProvider.setRouteSelector(mSelector);</strong>
+
+ // Return true to show the menu.
+ return true;
+}
+</pre>
+
+<p>Once you have made these changes to your app, you might expect the Cast button to appear in your
+ activity. Alas, it does not (unless your device is already paired with a Wireless Display). In
+ most cases, you must also connect with the media route framework, which is discussed in the next
+ section.
+</p>
+
+
+<h2 id="media-routes">Connecting to Media Routes</h2>
+
+<p>In order to connect to a media route selected by the user, your app must obtain the {@link
+ android.support.v7.media.MediaRouter} framework object and then attach a {@link
+ android.support.v7.media.MediaRouter.Callback} object. The callback object receives messages
+ from the media router framework when a route selected, changed or disconnected by the user.</p>
+
+<p>To obtain an instance of the {@link android.support.v7.media.MediaRouter} framework object,
+ call {@link android.support.v7.media.MediaRouter#getInstance MediaRouter.getInstance()}
+ from the {@link android.app.Activity#onCreate onCreate()} method of an activity that supports
+ the media router API.</p>
+
+<p class="note">
+ <strong>Note:</strong> The {@link android.support.v7.media.MediaRouter} object is a singleton
+ that is maintained by the framework. However, once your application obtains an instance of the
+ object you must retain that instance until your application terminates to prevent it from being
+ garbage collected.
+</p>
+
+
+<h3 id="create-mr-callback">Creating a MediaRouter callback</h3>
+
+<p>The media router framework communicates with an app through a callback object that
+ you attach to the {@link android.support.v7.media.MediaRouter} framework object. An app
+ that uses the media router framework must extend the {@link
+ android.support.v7.media.MediaRouter.Callback} object to receive messages when a media route is
+ connected and provide content to the connected device through that route.</p>
+
+<p>There are several methods in the callback that can be overwritten to receive messages about
+ media router events. At the minimum, your implementation of the {@link
+ android.support.v7.media.MediaRouter.Callback} class should override the following
+ methods:</p>
+
+<ul>
+ <li>{@link android.support.v7.media.MediaRouter.Callback#onRouteSelected onRouteSelected()}
+ — Called when the user connects to a media router output device.</li>
+ <li>{@link android.support.v7.media.MediaRouter.Callback#onRouteUnselected
+ onRouteUnselected()} — Called when the user disconnects from a media router output device.</li>
+ <li>{@link android.support.v7.media.MediaRouter.Callback#onRoutePresentationDisplayChanged
+ onRoutePresentationDisplayChanged()} — Called when the presentation display changes its
+ display metrics, such as changing from 720 pixel to 1080 pixel resolution.</li>
+</ul>
+
+<p>The methods of your {@link android.support.v7.media.MediaRouter.Callback}
+ implementation are the first opportunity to determine if the connected route is a remote playback
+ device, such as Chromecast, or a secondary output device, such as a Wireless Display device.
+ If your app supports both device types, then your implementation should branch here, as
+ shown in this sample code:</p>
+
+<pre>
+private final MediaRouter.Callback mMediaRouterCallback =
+ new MediaRouter.Callback() {
+
+ @Override
+ public void onRouteSelected(MediaRouter router, RouteInfo route) {
+ Log.d(TAG, "onRouteSelected: route=" + route);
+
+ if (route.supportsControlCategory(
+ MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){
+ // remote playback device
+ updateRemotePlayer(route);
+ } else {
+ // secondary output device
+ updatePresentation(route);
+ }
+ }
+
+ @Override
+ public void onRouteUnselected(MediaRouter router, RouteInfo route) {
+ Log.d(TAG, "onRouteUnselected: route=" + route);
+
+ if (route.supportsControlCategory(
+ MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){
+ // remote playback device
+ updateRemotePlayer(route);
+ } else {
+ // secondary output device
+ updatePresentation(route);
+ }
+ }
+
+ @Override
+ public void onRoutePresentationDisplayChanged(
+ MediaRouter router, RouteInfo route) {
+ Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route);
+
+ if (route.supportsControlCategory(
+ MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)){
+ // remote playback device
+ updateRemotePlayer(route);
+ } else {
+ // secondary output device
+ updatePresentation(route);
+ }
+ }
+}
+</pre>
+
+<p>After defining your callback object for the media router, you still need to attach it to
+ the main media router framework object. The next section discusses the appropriate way to attach
+ your callbacks for media routes.</p>
+
+
+<h3 id="attach-mr-callback">Attaching a callback to MediaRouter</h3>
+
+<p>Since media routes are a shared interface, your app must attach and detach your
+ {@link android.support.v7.media.MediaRouter.Callback} object as your app starts up and shuts
+ down. To accomplish this, you must add and remove your app's
+ callback object from the media router framework as part of your app's activity lifecycle. This
+ approach allows other apps to make use of media route outputs while your app
+ is in the background or not running.</p>
+
+<p class="note">
+ <strong>Note:</strong> If you are writing a music playback app and want to allow music to play
+ while your app is in the background, you must build a {@link android.app.Service} for playback
+ and connect that service and it's lifecycle to the media router framework.
+</p>
+
+<p>The following code sample demonstrates how to use the lifecycle methods to appropriately
+ add and remove your app's media router callback object:</p>
+
+<pre>
+public class MediaRouterPlaybackActivity extends ActionBarActivity {
+ private MediaRouter mMediaRouter;
+ private MediaRouteSelector mSelector;
+ private Callback mMediaRouterCallback;
+
+ // your app works with so the framework can discover them.
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Get the media router service.
+ mMediaRouter = MediaRouter.getInstance(this);
+ ...
+ }
+
+ // Add the callback on start to tell the media router what kinds of routes
+ // your app works with so the framework can discover them.
+ @Override
+ public void onStart() {
+ mMediaRouter.addCallback(mSelector, mMediaRouterCallback,
+ MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+ super.onStart();
+ }
+
+ // Remove the selector on stop to tell the media router that it no longer
+ // needs to discover routes for your app.
+ @Override
+ public void onStop() {
+ mMediaRouter.removeCallback(mMediaRouterCallback);
+ super.onStop();
+ }
+ ...
+}
+</pre>
+
+<p>You should add and remove the media router callback only in the {@link
+ android.app.Activity#onStart onStart()} and {@link android.app.Activity#onStop onStop()}
+ lifecycle methods. Do not include these calls in the {@link android.app.Activity#onResume
+ onResume()} or {@link android.app.Activity#onPause onPause()} methods.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> The media route framework also provides a
+ {@link android.support.v7.app.MediaRouteDiscoveryFragment} class which takes care of adding and
+ removing the call back for an activity.
+</p>
+
+<p>Now when you run your application, you should see a Cast button appear in your activity.
+ When you press the button the media router framework, a route selection dialog appears as shown
+ in figure 3, allowing your user to select an available media route. Make sure you have a
+ supported device available on your local network when testing this interface.</p>
+
+<p class="note">
+ <strong>Note:</strong> In order for Wireless Display routes to show up in the media route
+ selection dialog, users must enable this option in the Settings app. The option is under
+ the <em>Display</em> category and is called <em>Cast screen</em> on Android 4.4 (KitKat) and higher
+ devices and <em>Wireless Display</em> on Android 4.2.x (Jelly Bean) devices. For more information
+ on enabling this feature see this
+ <a href="https://support.google.com/nexus/answer/2865484">Wireless display</a> support page.
+</p>
+
+
+<h2 id="remote-playback">Remote Playback</h2>
+
+<p>The remote playback approach sends control commands to a secondary device to initiate playback
+ and to control playback that is in progress (pause, rewind, fast-forward, volume up and down).
+ Using this approach, the receiving device (such as a Chromecast) is responsible for retrieving
+ and rendering content.</p>
+
+<p>When your app supports this type of media route, you must create a {@link
+ android.support.v7.media.RemotePlaybackClient} object using a remote playback {@link
+ android.support.v7.media.MediaRouter.RouteInfo} object received through your app's
+ {@link android.support.v7.media.MediaRouter.Callback} object. The following sample
+ code demonstrates a controller method that creates a new remote playback client and sends it a
+ video for playback:</p>
+
+<pre>
+private void updateRemotePlayer(RouteInfo route) {
+ // Changed route: tear down previous client
+ if (mRoute != null && mRemotePlaybackClient != null) {
+ mRemotePlaybackClient.release();
+ mRemotePlaybackClient = null;
+ }
+
+ // Save new route
+ mRoute = route;
+
+ // Attach new playback client
+ mRemotePlaybackClient = new RemotePlaybackClient(this, mRoute);
+
+ // Send file for playback
+ mRemotePlaybackClient.play(Uri.parse(
+ "http://archive.org/download/Sintel/sintel-2048-stereo_512kb.mp4"),
+ "video/mp4", null, 0, null, new ItemActionCallback() {
+
+ @Override
+ public void onResult(Bundle data, String sessionId,
+ MediaSessionStatus sessionStatus,
+ String itemId, MediaItemStatus itemStatus) {
+ logStatus("play: succeeded for item " + itemId);
+ }
+
+ @Override
+ public void onError(String error, int code, Bundle data) {
+ logStatus("play: failed - error:"+ code +" - "+ error);
+ }
+ });
+ }
+}
+</pre>
+
+<p>The {@link android.support.v7.media.RemotePlaybackClient} class provides additional methods
+ for managing content playback. Here are a few of the key playback methods from the {@link
+ android.support.v7.media.RemotePlaybackClient} class:</p>
+
+<ul>
+ <li>{@link android.support.v7.media.RemotePlaybackClient#play play()} — Play a specific
+ media file, specified by a {@link android.net.Uri}.</li>
+ <li>{@link android.support.v7.media.RemotePlaybackClient#pause pause()} — Pause the
+ currently playing media track.</li>
+ <li>{@link android.support.v7.media.RemotePlaybackClient#resume resume()} — Continue
+ playing the current track after a pause command.</li>
+ <li>{@link android.support.v7.media.RemotePlaybackClient#seek seek()} — Move to a specific
+ position in the current track.</li>
+ <li>{@link android.support.v7.media.RemotePlaybackClient#release release()} — Tear down the
+ connection from your app to the remote playback device.</li>
+</ul>
+
+<p>You can use these methods to attach actions to playback controls you provide in your
+ app. Most of these methods also allow you to include a callback object so you can monitor
+ the progress of the playback task or control request.</p>
+
+<p>
+ The {@link android.support.v7.media.RemotePlaybackClient} class also supports queueing of
+ multiple media items for playback and management of the media queue. For a comprehensive sample
+ implementation of these features, see {@code SampleMediaRouterActivity} and its associated
+ classes in the v7 mediarouter support library sample
+ {@code <sdk>/extras/android/compatibility/v7/mediarouter}.
+</p>
+
+<p>
+ For additional information on using the Google Cast API for Chromecast devices, see the
+ <a href="http://developers.google.com/cast/">Google Cast</a> developer documentation.
+</p>
+
+
+<h2 id="secondary-output">Secondary Output</h2>
+
+<p>The secondary output approach sends prepared media content to a connected secondary device
+ for playback. Secondary devices can include televisions or wireless sound systems and can be
+ attached through wireless protocols or wires, such as an HDMI cable. With this approach, your
+ app is responsible for processing media content for playback (downloading, decoding,
+ synchronization of audio and video tracks), while the secondary device only outputs the content
+ in its final form.</p>
+
+<p class="note">
+ <strong>Note:</strong> Using the secondary output display routes with the media router framework
+ requires classes that are available only in Android 4.2 (API level 17) and higher, specifically the
+ {@link android.app.Presentation} class. If you are building an app that supports both
+ remote playback and secondary output devices, you must include checks that disable this code
+ below the supported Android version level.
+</p>
+
+
+<h3 id="pres-obj">Creating a Presentation object</h3>
+
+<p>When using a secondary output display with the media router framework, you create a {@link
+ android.app.Presentation} object that contains the content you want to show on that display. The
+ {@link android.app.Presentation} is extended from the {@link android.app.Dialog} class, so can
+ add layouts and views to a {@link android.app.Presentation}.</p>
+
+<p>You should be aware that the {@link android.app.Presentation} object has its own
+ {@link android.content.Context} and
+ {@link android.content.res.Resources},
+ separate from the app activity that created the object. Having a secondary
+ context is required, because the content of the {@link android.app.Presentation} is drawn on a
+ display that is separate from your app's display on the local Android device.
+ Specifically, the secondary display needs a separate context because it may need to load
+ resources based on its specific screen metrics.</p>
+
+<p>The following code sample shows a minimal implementation of a
+ {@link android.app.Presentation} object, including a {@link android.opengl.GLSurfaceView}
+ object.</p>
+
+<pre>
+public class SamplePresentation extends Presentation {
+ public SamplePresentation(Context outerContext, Display display) {
+ super(outerContext, display);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Notice that we get resources from the context of the Presentation
+ Resources resources = getContext().getResources();
+
+ // Inflate a layout.
+ setContentView(R.layout.presentation_with_media_router_content);
+
+ // Add presentation content here:
+ // Set up a surface view for visual interest
+ mSurfaceView = (GLSurfaceView)findViewById(R.id.surface_view);
+ mSurfaceView.setRenderer(new CubeRenderer(false));
+ }
+}
+</pre>
+
+
+<h3 id="pres-cntrlr">Creating a Presentation controller</h3>
+
+<p>In order to display a {@link android.app.Presentation} object, you should write a
+ controller layer that handles responses to the messages received by the {@link
+ android.support.v7.media.MediaRouter.Callback} object and manages the creation and
+ removal of the {@link android.app.Presentation} object. The controller layer should also handle
+ attaching presentations to a selected {@link android.view.Display} object, which represents the
+ separate physical display device chosen by the user. The controller layer can simply be a method
+ in the activity that supports a secondary display.</p>
+
+<p>The following code sample shows a controller layer for a {@link android.app.Presentation}
+ implemented as a single method. This method handles dismissing invalid presentations when a
+ {@link android.view.Display} is unselected or disconnected, and creates the {@link
+ android.app.Presentation} object when a display device is connected.</p>
+
+<pre>
+private void updatePresentation(RouteInfo route) {
+ // Get its Display if a valid route has been selected
+ Display selectedDisplay = null;
+ if (route != null) {
+ selectedDisplay = route.getPresentationDisplay();
+ }
+
+ // Dismiss the current presentation if the display has changed or no new
+ // route has been selected
+ if (mPresentation != null && mPresentation.getDisplay() != selectedDisplay) {
+ mPresentation.dismiss();
+ mPresentation = null;
+ }
+
+ // Show a new presentation if the previous one has been dismissed and a
+ // route has been selected.
+ if (mPresentation == null && selectedDisplay != null) {
+ // Initialize a new Presentation for the Display
+ mPresentation = new SamplePresentation(this, selectedDisplay);
+ mPresentation.setOnDismissListener(
+ new DialogInterface.OnDismissListener() {
+ // Listen for presentation dismissal and then remove it
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ if (dialog == mPresentation) {
+ mPresentation = null;
+ }
+ }
+ });
+
+ // Try to show the presentation, this might fail if the display has
+ // gone away in the meantime
+ try {
+ mPresentation.show();
+ } catch (WindowManager.InvalidDisplayException ex) {
+ // Couldn't show presentation - display was already removed
+ mPresentation = null;
+ }
+ }
+}
+</pre>
+
+<p class="note">
+ <strong>Note:</strong> When the a user connects to a Wireless Display, the media router
+ framework automatically provides a notification that it is displaying screen content on a
+ connected device.
+</p>
diff --git a/docs/html/images/mediarouter/mediarouter-actionbar.png b/docs/html/images/mediarouter/mediarouter-actionbar.png
new file mode 100644
index 0000000..f167054
--- /dev/null
+++ b/docs/html/images/mediarouter/mediarouter-actionbar.png
Binary files differ
diff --git a/docs/html/images/mediarouter/mediarouter-framework.png b/docs/html/images/mediarouter/mediarouter-framework.png
new file mode 100644
index 0000000..3541e1a
--- /dev/null
+++ b/docs/html/images/mediarouter/mediarouter-framework.png
Binary files differ
diff --git a/docs/html/images/mediarouter/mediarouter-selector-ui.png b/docs/html/images/mediarouter/mediarouter-selector-ui.png
new file mode 100644
index 0000000..acc39ca
--- /dev/null
+++ b/docs/html/images/mediarouter/mediarouter-selector-ui.png
Binary files differ
diff --git a/docs/html/index.jd b/docs/html/index.jd
index d976c1e..5d1788a 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -57,7 +57,7 @@
</div>
<div class="content-right col-4">
<h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Kiwi, Inc.</h1>
- <p>Game developer Kiwi has five of the top 25 grossing titles on Google Play. Hear how Google Play
+ <p>Game developer Kiwi has had five titles in the top 25 grossing on Google Play. Hear how Google Play
has helped them double revenue every six months.</p>
<p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p>
</div>
diff --git a/docs/html/samples/renderscript.jd b/docs/html/samples/renderscript.jd
new file mode 100644
index 0000000..2adec4d
--- /dev/null
+++ b/docs/html/samples/renderscript.jd
@@ -0,0 +1,11 @@
+page.title=Renderscript
+@jd:body
+
+
+<div id="samples" class="renderscript">
+</div>
+
+
+<script>
+ $(document).ready(showSamples);
+</script>
diff --git a/docs/html/samples/sensors.jd b/docs/html/samples/sensors.jd
new file mode 100644
index 0000000..c3a764f
--- /dev/null
+++ b/docs/html/samples/sensors.jd
@@ -0,0 +1,11 @@
+page.title=Sensors
+@jd:body
+
+
+<div id="samples" class="sensors">
+</div>
+
+
+<script>
+ $(document).ready(showSamples);
+</script>
diff --git a/docs/html/tools/help/avd-manager.jd b/docs/html/tools/help/avd-manager.jd
index ed90f43..20f6253 100644
--- a/docs/html/tools/help/avd-manager.jd
+++ b/docs/html/tools/help/avd-manager.jd
@@ -8,8 +8,11 @@
<p>You can launch the AVD Manager in one of the following ways:</p>
<ul>
- <li>In Eclipse: select <strong>Window > AVD Manager</strong>, or click
- the AVD Manager icon in the Eclipse toolbar.</li>
+ <li>In Eclipse: select <strong>Window > Android Virtual Device Manager</strong>, or click
+ the AVD Manager icon in the toolbar.</li>
+
+ <li>In Android Studio: select <strong>Tools > Android > AVD Manager</strong>, or click
+ the AVD Manager icon in the toolbar.</li>
<li>In other IDEs: Navigate to your SDK's <code>tools/</code> directory and execute
<code>android avd</code>.</li>
diff --git a/docs/html/tools/help/sdk-manager.jd b/docs/html/tools/help/sdk-manager.jd
index 276206f..57271bb 100644
--- a/docs/html/tools/help/sdk-manager.jd
+++ b/docs/html/tools/help/sdk-manager.jd
@@ -9,6 +9,8 @@
<ul>
<li>From Eclipse (with <a href="{@docRoot}tools/help/adt.html">ADT</a>),
select <strong>Window</strong> > <strong>Android SDK Manager</strong>.</li>
+ <li>From Android Studio, select <strong>Tools</strong> > <strong>Android</strong>
+ > <strong>SDK Manager</strong>.</li>
<li>On Windows, double-click the <code>SDK Manager.exe</code> file at the root of the Android
SDK directory.</li>
<li>On Mac or Linux, open a terminal and navigate to the <code>tools/</code> directory in the
diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd
index 1da51b5..749808f 100644
--- a/docs/html/tools/revisions/build-tools.jd
+++ b/docs/html/tools/revisions/build-tools.jd
@@ -74,10 +74,36 @@
revisions of the Build Tools are available in your SDK, refer to the <em>Installed Packages</em>
listing in the Android SDK Manager.</p>
-
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Build Tools, Revision 19.0.2</a> <em>(February 2014)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+
+ <dl>
+ <dt>Fixed RenderScript build issues:</dt>
+ <dd>
+ <ul>
+ <li>Fixed a problem with RenderScript bitcode encoding.
+ (<a href="http://b.android.com/64775">Issue 64775</a>)
+ </li>
+ <li>Fixed a problem with RenderScript missing math symbols
+ (<a href="http://b.android.com/64110">Issue 64110</a>)
+ </li>
+ </ul>
+ </dd>
+ </dl>
+ <p></p>
+
+ </div>
+</div>
+
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Build Tools, Revision 19.0.1</a> <em>(December 2013)</em>
</p>
<div class="toggle-content-toggleme">
diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd
index c5d1ef6..99a271f 100644
--- a/docs/html/tools/revisions/platforms.jd
+++ b/docs/html/tools/revisions/platforms.jd
@@ -87,19 +87,34 @@
</div>
+
<h3 id="gsi-4.4">Google APIs System Image</h3>
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png"
+class="toggle-content-img" alt="" />Revision 3</a> <em>(February 2014)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+
+ <p>This release includes
+ <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 4.2.42,
+ allowing you to test your application in an emulator using the latest Google Play services.</p>
+
+ </div>
+</div>
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png"
class="toggle-content-img" alt="" />Revision 2</a> <em>(December 2013)</em>
</p>
<div class="toggle-content-toggleme">
- <p>Maintenance release. This release includes
- <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 4.0.33,
- allowing you to test your application in an emulator using the latest Google Play services.</p>
+ <p>This release includes
+ <a href="{@docRoot}google/play-services/index.html">Google Play services</a> version 4.0.33.</p>
</div>
</div>
diff --git a/docs/html/tools/testing/testing_ui.jd b/docs/html/tools/testing/testing_ui.jd
index 701415e..4318a21 100644
--- a/docs/html/tools/testing/testing_ui.jd
+++ b/docs/html/tools/testing/testing_ui.jd
@@ -90,7 +90,7 @@
alt="User interface of uiautomatorviewer tool" height="327px" id="figure1"/>
</a>
<p class="img-caption">
- <strong>Figure 1.</strong> The {@code uiautomatorviewer} showing the captured interface of a test deviice.
+ <strong>Figure 1.</strong> The {@code uiautomatorviewer} showing the captured interface of a test device.
</p>
<p>To analyze the UI components of the application that you want to test:</p>
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index d6b73fd..7676143 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -400,7 +400,7 @@
* No color information is stored.
* With this configuration, each pixel requires 1 byte of memory.
*/
- ALPHA_8 (2),
+ ALPHA_8 (1),
/**
* Each pixel is stored on 2 bytes and only the RGB channels are
@@ -416,7 +416,7 @@
* This configuration may be useful when using opaque bitmaps
* that do not require high color fidelity.
*/
- RGB_565 (4),
+ RGB_565 (3),
/**
* Each pixel is stored on 2 bytes. The three RGB color channels
@@ -438,7 +438,7 @@
* it is advised to use {@link #ARGB_8888} instead.
*/
@Deprecated
- ARGB_4444 (5),
+ ARGB_4444 (4),
/**
* Each pixel is stored on 4 bytes. Each channel (RGB and alpha
@@ -448,13 +448,13 @@
* This configuration is very flexible and offers the best
* quality. It should be used whenever possible.
*/
- ARGB_8888 (6);
+ ARGB_8888 (5);
final int nativeInt;
@SuppressWarnings({"deprecation"})
private static Config sConfigs[] = {
- null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
+ null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
};
Config(int ni) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 9360558..2f4196a 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -28,6 +29,8 @@
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.GradientDrawable.GradientState;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.Xfermode;
@@ -49,8 +52,8 @@
* information, see the guide to <a
* href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
* <p>
- * Also see the {@link android.graphics.Bitmap} class, which handles the management and
- * transformation of raw bitmap graphics, and should be used when drawing to a
+ * Also see the {@link android.graphics.Bitmap} class, which handles the management and
+ * transformation of raw bitmap graphics, and should be used when drawing to a
* {@link android.graphics.Canvas}.
* </p>
*
@@ -68,13 +71,14 @@
Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
private BitmapState mBitmapState;
private Bitmap mBitmap;
+ private PorterDuffColorFilter mTintFilter;
private int mTargetDensity;
private final Rect mDstRect = new Rect(); // Gravity.apply() sets this
private boolean mApplyGravity;
private boolean mMutated;
-
+
// These are scaled to match the target density.
private int mBitmapWidth;
private int mBitmapHeight;
@@ -192,7 +196,7 @@
mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity);
mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity);
}
-
+
private void setBitmap(Bitmap bitmap) {
if (bitmap != mBitmap) {
mBitmap = bitmap;
@@ -277,7 +281,7 @@
*
* @param mipMap True if the bitmap should use mipmaps, false otherwise.
*
- * @see #hasMipMap()
+ * @see #hasMipMap()
*/
public void setMipMap(boolean mipMap) {
if (mBitmapState.mBitmap != null) {
@@ -292,7 +296,7 @@
* @return True if the mipmap hint is set, false otherwise. If the bitmap
* is null, this method always returns false.
*
- * @see #setMipMap(boolean)
+ * @see #setMipMap(boolean)
* @attr ref android.R.styleable#BitmapDrawable_mipMap
*/
public boolean hasMipMap() {
@@ -302,10 +306,10 @@
/**
* Enables or disables anti-aliasing for this drawable. Anti-aliasing affects
* the edges of the bitmap only so it applies only when the drawable is rotated.
- *
+ *
* @param aa True if the bitmap should be anti-aliased, false otherwise.
*
- * @see #hasAntiAlias()
+ * @see #hasAntiAlias()
*/
public void setAntiAlias(boolean aa) {
mBitmapState.mPaint.setAntiAlias(aa);
@@ -337,7 +341,7 @@
/**
* Indicates the repeat behavior of this drawable on the X axis.
- *
+ *
* @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
* {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
*/
@@ -347,10 +351,10 @@
/**
* Indicates the repeat behavior of this drawable on the Y axis.
- *
+ *
* @return {@link Shader.TileMode#CLAMP} if the bitmap does not repeat,
* {@link Shader.TileMode#REPEAT} or {@link Shader.TileMode#MIRROR} otherwise.
- */
+ */
public Shader.TileMode getTileModeY() {
return mBitmapState.mTileModeY;
}
@@ -360,11 +364,11 @@
* does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
* {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
* is smaller than this drawable.
- *
+ *
* @param mode The repeat mode for this drawable.
- *
- * @see #setTileModeY(android.graphics.Shader.TileMode)
- * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
+ *
+ * @see #setTileModeY(android.graphics.Shader.TileMode)
+ * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
*/
public void setTileModeX(Shader.TileMode mode) {
setTileModeXY(mode, mBitmapState.mTileModeY);
@@ -375,12 +379,12 @@
* does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
* {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
* is smaller than this drawable.
- *
+ *
* @param mode The repeat mode for this drawable.
- *
- * @see #setTileModeX(android.graphics.Shader.TileMode)
- * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
- */
+ *
+ * @see #setTileModeX(android.graphics.Shader.TileMode)
+ * @see #setTileModeXY(android.graphics.Shader.TileMode, android.graphics.Shader.TileMode)
+ */
public final void setTileModeY(Shader.TileMode mode) {
setTileModeXY(mBitmapState.mTileModeX, mode);
}
@@ -390,12 +394,12 @@
* does not repeat its bitmap. Using {@link Shader.TileMode#REPEAT} or
* {@link Shader.TileMode#MIRROR} the bitmap can be repeated (or tiled) if the bitmap
* is smaller than this drawable.
- *
+ *
* @param xmode The X repeat mode for this drawable.
* @param ymode The Y repeat mode for this drawable.
- *
+ *
* @see #setTileModeX(android.graphics.Shader.TileMode)
- * @see #setTileModeY(android.graphics.Shader.TileMode)
+ * @see #setTileModeY(android.graphics.Shader.TileMode)
*/
public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
final BitmapState state = mBitmapState;
@@ -457,66 +461,86 @@
@Override
public void draw(Canvas canvas) {
- Bitmap bitmap = mBitmap;
- if (bitmap != null) {
- final BitmapState state = mBitmapState;
- if (state.mRebuildShader) {
- Shader.TileMode tmx = state.mTileModeX;
- Shader.TileMode tmy = state.mTileModeY;
+ final Bitmap bitmap = mBitmap;
+ if (bitmap == null) {
+ return;
+ }
- if (tmx == null && tmy == null) {
- state.mPaint.setShader(null);
- } else {
- state.mPaint.setShader(new BitmapShader(bitmap,
- tmx == null ? Shader.TileMode.CLAMP : tmx,
- tmy == null ? Shader.TileMode.CLAMP : tmy));
- }
- state.mRebuildShader = false;
- copyBounds(mDstRect);
- }
-
- Shader shader = state.mPaint.getShader();
- final boolean needMirroring = needMirroring();
- if (shader == null) {
- if (mApplyGravity) {
- final int layoutDirection = getLayoutDirection();
- Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight,
- getBounds(), mDstRect, layoutDirection);
- mApplyGravity = false;
- }
- if (needMirroring) {
- canvas.save();
- // Mirror the bitmap
- canvas.translate(mDstRect.right - mDstRect.left, 0);
- canvas.scale(-1.0f, 1.0f);
- }
- canvas.drawBitmap(bitmap, null, mDstRect, state.mPaint);
- if (needMirroring) {
- canvas.restore();
- }
+ final BitmapState state = mBitmapState;
+ final Paint paint = state.mPaint;
+ if (state.mRebuildShader) {
+ final Shader.TileMode tmx = state.mTileModeX;
+ final Shader.TileMode tmy = state.mTileModeY;
+ if (tmx == null && tmy == null) {
+ paint.setShader(null);
} else {
- if (mApplyGravity) {
- copyBounds(mDstRect);
- mApplyGravity = false;
- }
- if (needMirroring) {
- // Mirror the bitmap
- updateMirrorMatrix(mDstRect.right - mDstRect.left);
- shader.setLocalMatrix(mMirrorMatrix);
- } else {
- if (mMirrorMatrix != null) {
- mMirrorMatrix = null;
- shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
- }
- }
- canvas.drawRect(mDstRect, state.mPaint);
+ paint.setShader(new BitmapShader(bitmap,
+ tmx == null ? Shader.TileMode.CLAMP : tmx,
+ tmy == null ? Shader.TileMode.CLAMP : tmy));
}
+
+ state.mRebuildShader = false;
+ copyBounds(mDstRect);
+ }
+
+ final boolean clearColorFilter;
+ if (mTintFilter != null && paint.getColorFilter() == null) {
+ paint.setColorFilter(mTintFilter);
+ clearColorFilter = true;
+ } else {
+ clearColorFilter = false;
+ }
+
+ final Shader shader = paint.getShader();
+ final boolean needMirroring = needMirroring();
+ if (shader == null) {
+ if (mApplyGravity) {
+ final int layoutDirection = getLayoutDirection();
+ Gravity.apply(state.mGravity, mBitmapWidth, mBitmapHeight,
+ getBounds(), mDstRect, layoutDirection);
+ mApplyGravity = false;
+ }
+
+ if (needMirroring) {
+ canvas.save();
+ // Mirror the bitmap
+ canvas.translate(mDstRect.right - mDstRect.left, 0);
+ canvas.scale(-1.0f, 1.0f);
+ }
+
+ canvas.drawBitmap(bitmap, null, mDstRect, paint);
+
+ if (needMirroring) {
+ canvas.restore();
+ }
+ } else {
+ if (mApplyGravity) {
+ copyBounds(mDstRect);
+ mApplyGravity = false;
+ }
+
+ if (needMirroring) {
+ // Mirror the bitmap
+ updateMirrorMatrix(mDstRect.right - mDstRect.left);
+ shader.setLocalMatrix(mMirrorMatrix);
+ } else {
+ if (mMirrorMatrix != null) {
+ mMirrorMatrix = null;
+ shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
+ }
+ }
+
+ canvas.drawRect(mDstRect, paint);
+ }
+
+ if (clearColorFilter) {
+ paint.setColorFilter(null);
}
}
@Override
public void setAlpha(int alpha) {
- int oldAlpha = mBitmapState.mPaint.getAlpha();
+ final int oldAlpha = mBitmapState.mPaint.getAlpha();
if (alpha != oldAlpha) {
mBitmapState.mPaint.setAlpha(alpha);
invalidateSelf();
@@ -535,6 +559,43 @@
}
/**
+ * Specifies a tint for this drawable.
+ * <p>
+ * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
+ * tint.
+ *
+ * @param tint Color state list to use for tinting this drawable, or null to
+ * clear the tint
+ */
+ public void setTint(ColorStateList tint) {
+ mBitmapState.mTint = tint;
+ if (mTintFilter == null) {
+ if (tint != null) {
+ final int color = tint.getColorForState(getState(), 0);
+ mTintFilter = new PorterDuffColorFilter(color, mBitmapState.mTintMode);
+ }
+ } else {
+ if (tint == null) {
+ mTintFilter = null;
+ }
+ }
+ invalidateSelf();
+ }
+
+ /**
+ * Specifies the blending mode used to apply tint.
+ *
+ * @param tintMode A Porter-Duff blending mode
+ */
+ public void setTintMode(Mode tintMode) {
+ mBitmapState.mTintMode = tintMode;
+ if (mTintFilter != null) {
+ mTintFilter.setMode(tintMode);
+ }
+ invalidateSelf();
+ }
+
+ /**
* @hide Candidate for future API inclusion
*/
public void setXfermode(Xfermode xfermode) {
@@ -558,11 +619,34 @@
}
@Override
+ protected boolean onStateChange(int[] stateSet) {
+ final ColorStateList tint = mBitmapState.mTint;
+ if (tint != null) {
+ final int newColor = tint.getColorForState(stateSet, 0);
+ final int oldColor = mTintFilter.getColor();
+ if (oldColor != newColor) {
+ mTintFilter.setColor(newColor);
+ invalidateSelf();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isStateful() {
+ final BitmapState s = mBitmapState;
+ return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
+ }
+
+ @Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs);
- TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.BitmapDrawable);
+ final BitmapState state = mBitmapState;
+ final TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.BitmapDrawable);
final int id = a.getResourceId(com.android.internal.R.styleable.BitmapDrawable_src, 0);
if (id == 0) {
@@ -574,7 +658,7 @@
throw new XmlPullParserException(parser.getPositionDescription() +
": <bitmap> requires a valid src attribute");
}
- mBitmapState.mBitmap = bitmap;
+ state.mBitmap = bitmap;
setBitmap(bitmap);
setTargetDensity(r.getDisplayMetrics());
setMipMap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_mipMap,
@@ -582,19 +666,16 @@
setAutoMirrored(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_autoMirrored,
false));
- if (a.hasValue(com.android.internal.R.styleable.BitmapDrawable_colorFilterColor)) {
- final int colorFilterColor = a.getColor(
- com.android.internal.R.styleable.BitmapDrawable_colorFilterColor, 0);
- final int modeValue = a.getInt(
- com.android.internal.R.styleable.BitmapDrawable_colorFilterMode,
- Mode.MULTIPLY.ordinal());
- final Mode mode = Drawable.parseColorFilterMode(modeValue);
- if (mode != null) {
- setColorFilter(colorFilterColor, mode);
- }
+ final int tintModeValue = a.getInt(
+ com.android.internal.R.styleable.BitmapDrawable_tintMode, -1);
+ state.mTintMode = Drawable.parseTintMode(tintModeValue, Mode.SRC_IN);
+ state.mTint = a.getColorStateList(com.android.internal.R.styleable.BitmapDrawable_tint);
+ if (state.mTint != null) {
+ final int color = state.mTint.getColorForState(getState(), 0);
+ mTintFilter = new PorterDuffColorFilter(color, mBitmapState.mTintMode);
}
- final Paint paint = mBitmapState.mPaint;
+ final Paint paint = state.mPaint;
paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias,
paint.isAntiAlias()));
paint.setFilterBitmap(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_filter,
@@ -648,6 +729,8 @@
final static class BitmapState extends ConstantState {
Bitmap mBitmap;
+ ColorStateList mTint;
+ Mode mTintMode;
int mChangingConfigurations;
int mGravity = Gravity.FILL;
Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS);
@@ -663,6 +746,8 @@
BitmapState(BitmapState bitmapState) {
mBitmap = bitmapState.mBitmap;
+ mTint = bitmapState.mTint;
+ mTintMode = bitmapState.mTintMode;
mChangingConfigurations = bitmapState.mChangingConfigurations;
mGravity = bitmapState.mGravity;
mTileModeX = bitmapState.mTileModeX;
@@ -696,11 +781,18 @@
private BitmapDrawable(BitmapState state, Resources res) {
mBitmapState = state;
+
if (res != null) {
mTargetDensity = res.getDisplayMetrics().densityDpi;
} else {
mTargetDensity = state.mTargetDensity;
}
+
+ if (state.mTint != null) {
+ final int color = state.mTint.getColorForState(getState(), 0);
+ mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+ }
+
setBitmap(state != null ? state.mBitmap : null);
}
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b81e1c0..a9cf115 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -19,6 +19,7 @@
import android.graphics.Insets;
import android.graphics.Xfermode;
import android.os.Trace;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -34,6 +35,7 @@
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.StateSet;
@@ -1137,15 +1139,21 @@
}
/**
- * Parses a {@link android.graphics.PorterDuff.Mode} from a colorFilterMode
+ * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
* attribute's enum value.
*/
- static PorterDuff.Mode parseColorFilterMode(int value) {
- final PorterDuff.Mode[] modes = PorterDuff.Mode.values();
- if (value >= 0 && value < modes.length) {
- return modes[value];
+ static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+ switch (value) {
+ case 0:
+ return Mode.SRC_IN;
+ case 1:
+ return Mode.SRC_ATOP;
+ case 2:
+ return Mode.MULTIPLY;
+ case 3:
+ return Mode.SCREEN;
}
- return null;
+ return defaultMode;
}
}
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index e654db1..46d57ad 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -32,6 +32,7 @@
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
+import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
@@ -112,6 +113,15 @@
*/
public static final int SWEEP_GRADIENT = 2;
+ /** Radius is in pixels. */
+ private static final int RADIUS_TYPE_PIXELS = 0;
+
+ /** Radius is a fraction of the base size. */
+ private static final int RADIUS_TYPE_FRACTION = 1;
+
+ /** Radius is a fraction of the bounds size. */
+ private static final int RADIUS_TYPE_FRACTION_PARENT = 2;
+
private GradientState mGradientState;
private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
@@ -130,6 +140,9 @@
private Path mRingPath;
private boolean mPathIsDirty = true;
+ /** Current gradient radius, valid when {@link #mRectIsDirty} is false. */
+ private float mGradientRadius;
+
/**
* Controls how the gradient is oriented relative to the drawable's bounds
*/
@@ -401,12 +414,27 @@
* @see #setGradientType(int)
*/
public void setGradientRadius(float gradientRadius) {
- mGradientState.setGradientRadius(gradientRadius);
+ mGradientState.setGradientRadius(gradientRadius, TypedValue.COMPLEX_UNIT_PX);
mRectIsDirty = true;
invalidateSelf();
}
/**
+ * Returns the radius of the gradient in pixels. The radius is valid only
+ * when the gradient type is set to {@link #RADIAL_GRADIENT}.
+ *
+ * @return Radius in pixels.
+ */
+ public float getGradientRadius() {
+ if (mGradientState.mGradient != RADIAL_GRADIENT) {
+ return 0;
+ }
+
+ ensureValidRect();
+ return mGradientRadius;
+ }
+
+ /**
* <p>Sets whether or not this drawable will honor its <code>level</code>
* property.</p>
* <p><strong>Note</strong>: changing this property will affect all instances
@@ -703,7 +731,7 @@
}
@Override
- public boolean onStateChange(int[] stateSet) {
+ protected boolean onStateChange(int[] stateSet) {
boolean invalidateSelf = false;
final GradientState s = mGradientState;
@@ -872,11 +900,27 @@
x0 = r.left + (r.right - r.left) * st.mCenterX;
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
- final float level = st.mUseLevel ? (float) getLevel() / 10000.0f : 1.0f;
+ float radius = st.mGradientRadius;
+ if (st.mGradientRadiusType == RADIUS_TYPE_FRACTION) {
+ radius *= Math.min(st.mWidth, st.mHeight);
+ } else if (st.mGradientRadiusType == RADIUS_TYPE_FRACTION_PARENT) {
+ radius *= Math.min(r.width(), r.height());
+ }
- mFillPaint.setShader(new RadialGradient(x0, y0,
- level * st.mGradientRadius, colors, null,
- Shader.TileMode.CLAMP));
+ if (st.mUseLevel) {
+ radius *= getLevel() / 10000.0f;
+ }
+
+ mGradientRadius = radius;
+
+ if (radius == 0) {
+ // We can't have a shader with zero radius, so let's
+ // have a very, very small radius.
+ radius = 0.001f;
+ }
+
+ mFillPaint.setShader(new RadialGradient(
+ x0, y0, radius, colors, null, Shader.TileMode.CLAMP));
} else if (st.mGradient == SWEEP_GRADIENT) {
x0 = r.left + (r.right - r.left) * st.mCenterX;
y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -1051,12 +1095,28 @@
break;
}
} else {
- TypedValue tv = a.peekValue(
+ final TypedValue tv = a.peekValue(
com.android.internal.R.styleable.GradientDrawableGradient_gradientRadius);
if (tv != null) {
- boolean radiusRel = tv.type == TypedValue.TYPE_FRACTION;
- st.mGradientRadius = radiusRel ?
- tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+ final float radius;
+ final int radiusType;
+ if (tv.type == TypedValue.TYPE_FRACTION) {
+ radius = tv.getFraction(1.0f, 1.0f);
+
+ final int unit = (tv.data >> TypedValue.COMPLEX_UNIT_SHIFT)
+ & TypedValue.COMPLEX_UNIT_MASK;
+ if (unit == TypedValue.COMPLEX_UNIT_FRACTION_PARENT) {
+ radiusType = RADIUS_TYPE_FRACTION_PARENT;
+ } else {
+ radiusType = RADIUS_TYPE_FRACTION;
+ }
+ } else {
+ radius = tv.getDimension(r.getDisplayMetrics());
+ radiusType = RADIUS_TYPE_PIXELS;
+ }
+
+ st.mGradientRadius = radius;
+ st.mGradientRadiusType = radiusType;
} else if (gradientType == RADIAL_GRADIENT) {
throw new XmlPullParserException(
a.getPositionDescription()
@@ -1218,6 +1278,7 @@
private float mCenterX = 0.5f;
private float mCenterY = 0.5f;
private float mGradientRadius = 0.5f;
+ private int mGradientRadiusType = RADIUS_TYPE_PIXELS;
private boolean mUseLevel;
private boolean mUseLevelForShape;
private boolean mOpaque;
@@ -1259,6 +1320,7 @@
mCenterX = state.mCenterX;
mCenterY = state.mCenterY;
mGradientRadius = state.mGradientRadius;
+ mGradientRadiusType = state.mGradientRadiusType;
mUseLevel = state.mUseLevel;
mUseLevelForShape = state.mUseLevelForShape;
mOpaque = state.mOpaque;
@@ -1375,8 +1437,9 @@
mHeight = height;
}
- public void setGradientRadius(float gradientRadius) {
+ public void setGradientRadius(float gradientRadius, int type) {
mGradientRadius = gradientRadius;
+ mGradientRadiusType = type;
}
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 515d3c1..aab1fd9 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -30,6 +31,7 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.BitmapDrawable.BitmapState;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.LayoutDirection;
@@ -59,6 +61,7 @@
private static final boolean DEFAULT_DITHER = false;
private NinePatchState mNinePatchState;
private NinePatch mNinePatch;
+ private PorterDuffColorFilter mTintFilter;
private Rect mPadding;
private Insets mOpticalInsets = Insets.NONE;
private Paint mPaint;
@@ -136,10 +139,14 @@
// lazy allocation of a paint
setDither(state.mDither);
}
- if (state.mColorFilter != null) {
- setColorFilter(state.mColorFilter);
+
+ if (state.mTint != null) {
+ final int color = state.mTint.getColorForState(getState(), 0);
+ mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
}
+
setAutoMirrored(state.mAutoMirrored);
+
if (mNinePatch != null) {
computeBitmapSize();
}
@@ -225,6 +232,15 @@
@Override
public void draw(Canvas canvas) {
final Rect bounds = getBounds();
+
+ final boolean clearColorFilter;
+ if (mTintFilter != null && getPaint().getColorFilter() == null) {
+ mPaint.setColorFilter(mTintFilter);
+ clearColorFilter = true;
+ } else {
+ clearColorFilter = false;
+ }
+
final boolean needsMirroring = needsMirroring();
if (needsMirroring) {
canvas.save();
@@ -232,10 +248,16 @@
canvas.translate(bounds.right - bounds.left, 0);
canvas.scale(-1.0f, 1.0f);
}
+
mNinePatch.draw(canvas, bounds, mPaint);
+
if (needsMirroring) {
canvas.restore();
}
+
+ if (clearColorFilter) {
+ mPaint.setColorFilter(null);
+ }
}
@Override
@@ -295,6 +317,43 @@
invalidateSelf();
}
+ /**
+ * Specifies a tint for this drawable.
+ * <p>
+ * Setting a color filter via {@link #setColorFilter(ColorFilter)} overrides
+ * tint.
+ *
+ * @param tint Color state list to use for tinting this drawable, or null to
+ * clear the tint
+ */
+ public void setTint(ColorStateList tint) {
+ mNinePatchState.mTint = tint;
+ if (mTintFilter == null) {
+ if (tint != null) {
+ final int color = tint.getColorForState(getState(), 0);
+ mTintFilter = new PorterDuffColorFilter(color, mNinePatchState.mTintMode);
+ }
+ } else {
+ if (tint == null) {
+ mTintFilter = null;
+ }
+ }
+ invalidateSelf();
+ }
+
+ /**
+ * Specifies the blending mode used to apply tint.
+ *
+ * @param tintMode A Porter-Duff blending mode
+ */
+ public void setTintMode(Mode tintMode) {
+ mNinePatchState.mTintMode = tintMode;
+ if (mTintFilter != null) {
+ mTintFilter.setMode(tintMode);
+ }
+ invalidateSelf();
+ }
+
@Override
public void setDither(boolean dither) {
//noinspection PointlessBooleanExpression
@@ -302,6 +361,7 @@
// Fast common case -- leave at default dither.
return;
}
+
getPaint().setDither(dither);
invalidateSelf();
}
@@ -376,17 +436,14 @@
new NinePatch(bitmap, bitmap.getNinePatchChunk()), padding, opticalInsets, dither,
automirrored);
- if (a.hasValue(com.android.internal.R.styleable.NinePatchDrawable_colorFilterColor)) {
- final int colorFilterColor = a.getColor(
- com.android.internal.R.styleable.NinePatchDrawable_colorFilterColor, 0);
- final int modeValue = a.getInt(
- com.android.internal.R.styleable.NinePatchDrawable_colorFilterMode,
- Mode.MULTIPLY.ordinal());
- final Mode mode = Drawable.parseColorFilterMode(modeValue);
- if (mode != null) {
- // This will be applied to the paint by setNinePatchState().
- ninePatchState.mColorFilter = new PorterDuffColorFilter(colorFilterColor, mode);
- }
+ final int tintModeValue = a.getInt(
+ com.android.internal.R.styleable.NinePatchDrawable_tintMode, -1);
+ ninePatchState.mTintMode = Drawable.parseTintMode(tintModeValue, Mode.SRC_IN);
+ ninePatchState.mTint = a.getColorStateList(
+ com.android.internal.R.styleable.NinePatchDrawable_tint);
+ if (ninePatchState.mTint != null) {
+ final int color = ninePatchState.mTint.getColorForState(getState(), 0);
+ mTintFilter = new PorterDuffColorFilter(color, ninePatchState.mTintMode);
}
setNinePatchState(ninePatchState, r);
@@ -461,15 +518,38 @@
return this;
}
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final ColorStateList tint = mNinePatchState.mTint;
+ if (tint != null) {
+ final int newColor = tint.getColorForState(stateSet, 0);
+ final int oldColor = mTintFilter.getColor();
+ if (oldColor != newColor) {
+ mTintFilter.setColor(newColor);
+ invalidateSelf();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean isStateful() {
+ final NinePatchState s = mNinePatchState;
+ return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
+ }
+
final static class NinePatchState extends ConstantState {
- final NinePatch mNinePatch;
- final Rect mPadding;
- final Insets mOpticalInsets;
- final boolean mDither;
+ NinePatch mNinePatch;
+ ColorStateList mTint;
+ Mode mTintMode;
+ Rect mPadding;
+ Insets mOpticalInsets;
+ boolean mDither;
int mChangingConfigurations;
int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
boolean mAutoMirrored;
- ColorFilter mColorFilter;
NinePatchState(NinePatch ninePatch, Rect padding) {
this(ninePatch, padding, new Rect(), DEFAULT_DITHER, false);
@@ -491,16 +571,16 @@
// Copy constructor
NinePatchState(NinePatchState state) {
- // Note we don't copy the nine patch because it is immutable.
+ // We don't deep-copy any fields because they are all immutable.
mNinePatch = state.mNinePatch;
- // Note we don't copy the padding because it is immutable.
+ mTint = state.mTint;
+ mTintMode = state.mTintMode;
mPadding = state.mPadding;
mOpticalInsets = state.mOpticalInsets;
mDither = state.mDither;
mChangingConfigurations = state.mChangingConfigurations;
mTargetDensity = state.mTargetDensity;
mAutoMirrored = state.mAutoMirrored;
- mColorFilter = state.mColorFilter;
}
@Override
diff --git a/graphics/java/android/graphics/drawable/RevealDrawable.java b/graphics/java/android/graphics/drawable/RevealDrawable.java
index 38765e8..91de638 100644
--- a/graphics/java/android/graphics/drawable/RevealDrawable.java
+++ b/graphics/java/android/graphics/drawable/RevealDrawable.java
@@ -18,7 +18,6 @@
import android.content.res.Resources;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
@@ -233,16 +232,14 @@
getDrawable(0).draw(canvas);
+ final Rect bounds = getBounds();
final ArrayList<Ripple> activeRipples = mActiveRipples;
- if (layerCount == 1 || activeRipples == null || activeRipples.isEmpty()) {
+ if (layerCount == 1 || bounds.isEmpty() || activeRipples == null
+ || activeRipples.isEmpty()) {
// Nothing to reveal, we're done here.
return;
}
- final Rect bounds = getBounds();
- final int width = bounds.width();
- final int height = bounds.height();
-
if (mRipplePaint == null) {
mRipplePaint = new Paint();
mRipplePaint.setAntiAlias(true);
@@ -260,7 +257,11 @@
n--;
} else {
if (layerSaveCount < 0) {
- layerSaveCount = canvas.saveLayer(0, 0, width, height, null, 0);
+ layerSaveCount = canvas.saveLayer(
+ bounds.left, bounds.top, bounds.right, bounds.bottom, null, 0);
+ // Ripples must be clipped to bounds, otherwise SRC_IN will
+ // miss them and we'll get artifacts.
+ canvas.clipRect(bounds);
}
needsMask |= ripple.draw(canvas, mRipplePaint);
@@ -279,7 +280,8 @@
// TODO: When Drawable.setXfermode() is supported by all drawables,
// we won't need an extra layer.
- canvas.saveLayer(0, 0, width, height, mMaskingPaint, 0);
+ canvas.saveLayer(
+ bounds.left, bounds.top, bounds.right, bounds.bottom, mMaskingPaint, 0);
getDrawable(1).draw(canvas);
}
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index cbe20dc..618afb8 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -32,10 +32,10 @@
private static final TimeInterpolator INTERPOLATOR = new DecelerateInterpolator(2.0f);
/** Starting radius for a ripple. */
- private static final int STARTING_RADIUS_DP = 40;
+ private static final int STARTING_RADIUS_DP = 16;
/** Radius when finger is outside view bounds. */
- private static final int OUTSIDE_RADIUS_DP = 40;
+ private static final int OUTSIDE_RADIUS_DP = 16;
/** Margin when constraining outside touches (fraction of outer radius). */
private static final float OUTSIDE_MARGIN = 0.8f;
diff --git a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
index 1bfdc4d..6fbcb53 100644
--- a/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
+++ b/graphics/java/android/graphics/drawable/TouchFeedbackDrawable.java
@@ -25,7 +25,6 @@
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.Xfermode;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -79,7 +78,7 @@
private Paint mRipplePaint;
/** Target density of the display into which ripples are drawn. */
- private int mTargetDensity;
+ private float mDensity = 1.0f;
/** Whether the animation runnable has been posted. */
private boolean mAnimating;
@@ -90,9 +89,7 @@
TouchFeedbackDrawable(TouchFeedbackState state, Resources res) {
if (res != null) {
- mTargetDensity = res.getDisplayMetrics().densityDpi;
- } else if (state != null) {
- mTargetDensity = state.mTargetDensity;
+ mDensity = res.getDisplayMetrics().density;
}
mState = state;
@@ -115,7 +112,7 @@
}
@Override
- public boolean onStateChange(int[] stateSet) {
+ protected boolean onStateChange(int[] stateSet) {
final ColorStateList stateList = mState.mColorStateList;
if (stateList != null && mRipplePaint != null) {
final int newColor = stateList.getColorForState(stateSet, 0);
@@ -143,32 +140,30 @@
return mState.mColorStateList != null && mState.mColorStateList.isStateful();
}
- /**
- * Set the density at which this drawable will be rendered.
- *
- * @param density The density scale for this drawable.
- */
- public void setTargetDensity(int density) {
- if (mTargetDensity != density) {
- mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
- // TODO: Update density in ripples?
- invalidateSelf();
- }
- }
-
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs);
- final TypedArray a = r.obtainAttributes(attrs,
- com.android.internal.R.styleable.ColorDrawable);
+ final TypedArray a = r.obtainAttributes(
+ attrs, com.android.internal.R.styleable.ColorDrawable);
mState.mColorStateList = a.getColorStateList(
com.android.internal.R.styleable.ColorDrawable_color);
a.recycle();
- mState.mXfermode = null; //new PorterDuffXfermode(Mode.SRC_ATOP);
- mState.mProjected = false;
+ setTargetDensity(r.getDisplayMetrics());
+ }
+
+ /**
+ * Set the density at which this drawable will be rendered.
+ *
+ * @param metrics The display metrics for this drawable.
+ */
+ private void setTargetDensity(DisplayMetrics metrics) {
+ if (mDensity != metrics.density) {
+ mDensity = metrics.density;
+ invalidateSelf();
+ }
}
/**
@@ -196,12 +191,13 @@
final Rect bounds = getBounds();
final Ripple newRipple = new Ripple(bounds, padding, bounds.exactCenterX(),
- bounds.exactCenterY(), mTargetDensity);
+ bounds.exactCenterY(), mDensity);
newRipple.enter();
mActiveRipples.add(newRipple);
mTouchedRipples.put(id, newRipple);
} else {
+ // TODO: How do we want to respond to movement?
//ripple.move(x, y);
}
@@ -296,7 +292,6 @@
mRipplePaint.setAntiAlias(true);
}
- mRipplePaint.setXfermode(mState.mXfermode);
mRipplePaint.setColor(color);
final int restoreCount = canvas.save();
@@ -338,18 +333,17 @@
return dirtyBounds;
}
- private static class TouchFeedbackState extends ConstantState {
- private ColorStateList mColorStateList;
- private Xfermode mXfermode;
- private int mTargetDensity;
- private boolean mProjected;
+ @Override
+ public ConstantState getConstantState() {
+ return mState;
+ }
+
+ static class TouchFeedbackState extends ConstantState {
+ ColorStateList mColorStateList;
public TouchFeedbackState(TouchFeedbackState orig) {
if (orig != null) {
mColorStateList = orig.mColorStateList;
- mXfermode = orig.mXfermode;
- mTargetDensity = orig.mTargetDensity;
- mProjected = orig.mProjected;
}
}
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 503377c..a13dd16 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -70,6 +70,12 @@
class AssetManager : public AAssetManager {
public:
static const char* RESOURCES_FILENAME;
+ static const char* IDMAP_BIN;
+ static const char* OVERLAY_DIR;
+ static const char* TARGET_PACKAGE_NAME;
+ static const char* TARGET_APK_PATH;
+ static const char* IDMAP_DIR;
+
typedef enum CacheMode {
CACHE_UNKNOWN = 0,
CACHE_OFF, // don't try to cache file locations
@@ -94,6 +100,7 @@
* newly-added asset source.
*/
bool addAssetPath(const String8& path, int32_t* cookie);
+ bool addOverlayPath(const String8& path, int32_t* cookie);
/*
* Convenience for adding the standard system assets. Uses the
@@ -272,19 +279,14 @@
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
- bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
- const String8& idmapPath);
-
- bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
- const String8& idmapPath);
-
Asset* openIdmapLocked(const struct asset_path& ap) const;
- bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc);
+ void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath,
+ ResTable* sharedRes, size_t offset) const;
class SharedZip : public RefBase {
public:
- static sp<SharedZip> get(const String8& path);
+ static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
ZipFileRO* getZip();
@@ -295,6 +297,9 @@
ResTable* setResourceTable(ResTable* res);
bool isUpToDate();
+
+ void addOverlay(const asset_path& ap);
+ bool getOverlay(size_t idx, asset_path* out) const;
protected:
~SharedZip();
@@ -310,6 +315,8 @@
Asset* mResourceTableAsset;
ResTable* mResourceTable;
+ Vector<asset_path> mOverlays;
+
static Mutex gLock;
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
};
@@ -342,6 +349,9 @@
static String8 getPathName(const char* path);
bool isUpToDate();
+
+ void addOverlay(const String8& path, const asset_path& overlay);
+ bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
private:
void closeZip(int idx);
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 0f51826..a0bae12 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1638,39 +1638,21 @@
// Return value: on success: NO_ERROR; caller is responsible for free-ing
// outData (using free(3)). On failure, any status_t value other than
// NO_ERROR; the caller should not free outData.
- status_t createIdmap(const ResTable& overlay, uint32_t targetCrc, uint32_t overlayCrc,
- void** outData, size_t* outSize) const;
-
status_t createIdmap(const ResTable& overlay,
uint32_t targetCrc, uint32_t overlayCrc,
const char* targetPath, const char* overlayPath,
- void** outData, size_t* outSize) const
- {
- (void)targetPath;
- (void)overlayPath;
- return createIdmap(overlay, targetCrc, overlayCrc, outData, outSize);
- }
+ void** outData, size_t* outSize) const;
enum {
- IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
+ IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t) + 2 * 256,
};
// Retrieve idmap meta-data.
//
// This function only requires the idmap header (the first
// IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
static bool getIdmapInfo(const void* idmap, size_t size,
- uint32_t* pTargetCrc, uint32_t* pOverlayCrc);
-
- static bool getIdmapInfo(const void* idmap, size_t size,
uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
- String8* pTargetPath, String8* pOverlayPath)
- {
- if (*pTargetPath)
- *pTargetPath = String8();
- if (*pOverlayPath)
- *pOverlayPath = String8();
- return getIdmapInfo(idmap, size, pTargetCrc, pOverlayCrc);
- }
+ String8* pTargetPath, String8* pOverlayPath);
void print(bool inclValues) const;
static String8 normalizeForOutput(const char* input);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index a24a8b3..64363d4 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -41,10 +41,8 @@
#include <assert.h>
#include <dirent.h>
#include <errno.h>
-#include <fcntl.h>
+#include <string.h> // strerror
#include <strings.h>
-#include <sys/stat.h>
-#include <unistd.h>
#ifndef TEMP_FAILURE_RETRY
/* Used to retry syscalls that can return EINTR. */
@@ -75,7 +73,7 @@
static const char* kAssetsRoot = "assets";
static const char* kAppZipName = NULL; //"classes.jar";
static const char* kSystemAssets = "framework/framework-res.apk";
-static const char* kIdmapCacheDir = "resource-cache";
+static const char* kResourceCache = "resource-cache";
static const char* kExcludeExtension = ".EXCLUDE";
@@ -84,15 +82,19 @@
static volatile int32_t gCount = 0;
const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
+const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
+const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
+const char* AssetManager::TARGET_PACKAGE_NAME = "android";
+const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
+const char* AssetManager::IDMAP_DIR = "/data/resource-cache";
namespace {
- // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
String8 idmapPathForPackagePath(const String8& pkgPath)
{
const char* root = getenv("ANDROID_DATA");
LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
String8 path(root);
- path.appendPath(kIdmapCacheDir);
+ path.appendPath(kResourceCache);
char buf[256]; // 256 chars should be enough for anyone...
strncpy(buf, pkgPath.string(), 255);
@@ -210,37 +212,78 @@
*cookie = static_cast<int32_t>(mAssetPaths.size());
}
- // add overlay packages for /system/framework; apps are handled by the
- // (Java) package manager
- if (strncmp(path.string(), "/system/framework/", 18) == 0) {
- // When there is an environment variable for /vendor, this
- // should be changed to something similar to how ANDROID_ROOT
- // and ANDROID_DATA are used in this file.
- String8 overlayPath("/vendor/overlay/framework/");
- overlayPath.append(path.getPathLeaf());
- if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {
- asset_path oap;
- oap.path = overlayPath;
- oap.type = ::getFileType(overlayPath.string());
- bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay
- if (addOverlay) {
- oap.idmap = idmapPathForPackagePath(overlayPath);
-
- if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) {
- addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);
- }
- }
- if (addOverlay) {
- mAssetPaths.add(oap);
- } else {
- ALOGW("failed to add overlay package %s\n", overlayPath.string());
- }
- }
+#ifdef HAVE_ANDROID_OS
+ // Load overlays, if any
+ asset_path oap;
+ for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
+ mAssetPaths.add(oap);
}
+#endif
return true;
}
+bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
+{
+ const String8 idmapPath = idmapPathForPackagePath(packagePath);
+
+ AutoMutex _l(mLock);
+
+ for (size_t i = 0; i < mAssetPaths.size(); ++i) {
+ if (mAssetPaths[i].idmap == idmapPath) {
+ *cookie = static_cast<int32_t>(i + 1);
+ return true;
+ }
+ }
+
+ Asset* idmap = NULL;
+ if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) {
+ ALOGW("failed to open idmap file %s\n", idmapPath.string());
+ return false;
+ }
+
+ String8 targetPath;
+ String8 overlayPath;
+ if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(),
+ NULL, NULL, &targetPath, &overlayPath)) {
+ ALOGW("failed to read idmap file %s\n", idmapPath.string());
+ delete idmap;
+ return false;
+ }
+ delete idmap;
+
+ if (overlayPath != packagePath) {
+ ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n",
+ idmapPath.string(), packagePath.string(), overlayPath.string());
+ return false;
+ }
+ if (access(targetPath.string(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno));
+ return false;
+ }
+ if (access(idmapPath.string(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ if (access(overlayPath.string(), R_OK) != 0) {
+ ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno));
+ return false;
+ }
+
+ asset_path oap;
+ oap.path = overlayPath;
+ oap.type = ::getFileType(overlayPath.string());
+ oap.idmap = idmapPath;
+#if 0
+ ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n",
+ targetPath.string(), overlayPath.string(), idmapPath.string());
+#endif
+ mAssetPaths.add(oap);
+ *cookie = static_cast<int32_t>(mAssetPaths.size());
+
+ return true;
+ }
+
bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize)
{
@@ -257,158 +300,13 @@
ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
return false;
}
- tables[i].add(ass, 1, false);
+ tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */);
}
return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
}
-bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
- const String8& idmapPath)
-{
- struct stat st;
- if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) {
- if (errno == ENOENT) {
- return true; // non-existing idmap is always stale
- } else {
- ALOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno));
- return false;
- }
- }
- if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
- ALOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size);
- return false;
- }
- int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY));
- if (fd == -1) {
- ALOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno));
- return false;
- }
- char buf[ResTable::IDMAP_HEADER_SIZE_BYTES];
- ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES;
- for (;;) {
- ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft,
- bytesLeft));
- if (r < 0) {
- TEMP_FAILURE_RETRY(close(fd));
- return false;
- }
- bytesLeft -= r;
- if (bytesLeft == 0) {
- break;
- }
- }
- TEMP_FAILURE_RETRY(close(fd));
-
- uint32_t cachedOriginalCrc, cachedOverlayCrc;
- if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES,
- &cachedOriginalCrc, &cachedOverlayCrc)) {
- return false;
- }
-
- uint32_t actualOriginalCrc, actualOverlayCrc;
- if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) {
- return false;
- }
- if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) {
- return false;
- }
- return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc;
-}
-
-bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename,
- uint32_t* pCrc)
-{
- asset_path ap;
- ap.path = zipPath;
- const ZipFileRO* zip = getZipFileLocked(ap);
- if (zip == NULL) {
- return false;
- }
- const ZipEntryRO entry = zip->findEntryByName(entryFilename);
- if (entry == NULL) {
- return false;
- }
-
- const bool gotInfo = zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc);
- zip->releaseEntry(entry);
-
- return gotInfo;
-}
-
-bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
- const String8& idmapPath)
-{
- ALOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n",
- __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string());
- ResTable tables[2];
- const String8* paths[2] = { &originalPath, &overlayPath };
- uint32_t originalCrc, overlayCrc;
- bool retval = false;
- ssize_t offset = 0;
- int fd = 0;
- uint32_t* data = NULL;
- size_t size;
-
- for (int i = 0; i < 2; ++i) {
- asset_path ap;
- ap.type = kFileTypeRegular;
- ap.path = *paths[i];
- Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
- if (ass == NULL) {
- ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
- goto error;
- }
- tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */);
- }
-
- if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) {
- ALOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string());
- goto error;
- }
- if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) {
- ALOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string());
- goto error;
- }
-
- if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc,
- (void**)&data, &size) != NO_ERROR) {
- ALOGW("failed to generate idmap data for file %s\n", idmapPath.string());
- goto error;
- }
-
- // This should be abstracted (eg replaced by a stand-alone
- // application like dexopt, triggered by something equivalent to
- // installd).
- fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
- if (fd == -1) {
- ALOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno));
- goto error_free;
- }
- for (;;) {
- ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size));
- if (written < 0) {
- ALOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(),
- strerror(errno));
- goto error_close;
- }
- size -= (size_t)written;
- offset += written;
- if (size == 0) {
- break;
- }
- }
-
- retval = true;
-error_close:
- TEMP_FAILURE_RETRY(close(fd));
-error_free:
- free(data);
-error:
- return retval;
-}
-
bool AssetManager::addDefaultAssets()
{
const char* root = getenv("ANDROID_ROOT");
@@ -676,6 +574,10 @@
// which we want to avoid parsing every time.
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.getZipResourceTable(ap.path);
+ if (sharedRes != NULL) {
+ // skip ahead the number of system overlay packages preloaded
+ i += sharedRes->getTableCount() - 1;
+ }
}
if (sharedRes == NULL) {
ass = const_cast<AssetManager*>(this)->
@@ -699,6 +601,14 @@
ALOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
sharedRes->add(ass, i + 1, false, idmap);
+#ifdef HAVE_ANDROID_OS
+ const char* data = getenv("ANDROID_DATA");
+ LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
+ String8 overlaysListPath(data);
+ overlaysListPath.appendPath(kResourceCache);
+ overlaysListPath.appendPath("overlays.list");
+ addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, i);
+#endif
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
@@ -773,6 +683,46 @@
return ass;
}
+void AssetManager::addSystemOverlays(const char* pathOverlaysList,
+ const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const
+{
+ FILE* fin = fopen(pathOverlaysList, "r");
+ if (fin == NULL) {
+ return;
+ }
+
+ char buf[1024];
+ while (fgets(buf, sizeof(buf), fin)) {
+ // format of each line:
+ // <path to apk><space><path to idmap><newline>
+ char* space = strchr(buf, ' ');
+ char* newline = strchr(buf, '\n');
+ asset_path oap;
+
+ if (space == NULL || newline == NULL || newline < space) {
+ continue;
+ }
+
+ oap.path = String8(buf, space - buf);
+ oap.type = kFileTypeRegular;
+ oap.idmap = String8(space + 1, newline - space - 1);
+
+ Asset* oass = const_cast<AssetManager*>(this)->
+ openNonAssetInPathLocked("resources.arsc",
+ Asset::ACCESS_BUFFER,
+ oap);
+
+ if (oass != NULL) {
+ Asset* oidmap = openIdmapLocked(oap);
+ offset++;
+ sharedRes->add(oass, offset + 1, false, oidmap);
+ const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
+ const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
+ }
+ }
+ fclose(fin);
+}
+
const ResTable& AssetManager::getResources(bool required) const
{
const ResTable* rt = getResTable(required);
@@ -1831,7 +1781,8 @@
}
}
-sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path)
+sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path,
+ bool createIfNotPresent)
{
AutoMutex _l(gLock);
time_t modWhen = getFileModDate(path);
@@ -1839,6 +1790,9 @@
if (zip != NULL && zip->mModWhen == modWhen) {
return zip;
}
+ if (zip == NULL && !createIfNotPresent) {
+ return NULL;
+ }
zip = new SharedZip(path, modWhen);
gOpen.add(path, zip);
return zip;
@@ -1897,6 +1851,20 @@
return mModWhen == modWhen;
}
+void AssetManager::SharedZip::addOverlay(const asset_path& ap)
+{
+ mOverlays.add(ap);
+}
+
+bool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const
+{
+ if (idx >= mOverlays.size()) {
+ return false;
+ }
+ *out = mOverlays[idx];
+ return true;
+}
+
AssetManager::SharedZip::~SharedZip()
{
//ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
@@ -2020,6 +1988,22 @@
return true;
}
+void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay)
+{
+ int idx = getIndex(path);
+ sp<SharedZip> zip = mZipFile[idx];
+ zip->addOverlay(overlay);
+}
+
+bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const
+{
+ sp<SharedZip> zip = SharedZip::get(path, false);
+ if (zip == NULL) {
+ return false;
+ }
+ return zip->getOverlay(idx, out);
+}
+
/*
* Compute the zip file's index.
*
diff --git a/libs/androidfw/BackupData.cpp b/libs/androidfw/BackupData.cpp
index 4e3b522..1a5c55c 100644
--- a/libs/androidfw/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -59,9 +59,10 @@
BackupDataWriter::BackupDataWriter(int fd)
:m_fd(fd),
m_status(NO_ERROR),
- m_pos(0),
m_entityCount(0)
{
+ m_pos = (ssize_t) lseek(fd, 0, SEEK_CUR);
+ if (DEBUG) ALOGI("BackupDataWriter(%d) @ %ld", fd, (long)m_pos);
}
BackupDataWriter::~BackupDataWriter()
@@ -184,10 +185,11 @@
:m_fd(fd),
m_done(false),
m_status(NO_ERROR),
- m_pos(0),
m_entityCount(0)
{
memset(&m_header, 0, sizeof(m_header));
+ m_pos = (ssize_t) lseek(fd, 0, SEEK_CUR);
+ if (DEBUG) ALOGI("BackupDataReader(%d) @ %ld", fd, (long)m_pos);
}
BackupDataReader::~BackupDataReader()
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index be163c2..51f59f6 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -101,21 +101,20 @@
if ((ssize_t)size <= (dataEnd-((const uint8_t*)chunk))) {
return NO_ERROR;
}
- ALOGW("%s data size %p extends beyond resource end %p.",
- name, (void*)size,
- (void*)(dataEnd-((const uint8_t*)chunk)));
+ ALOGW("%s data size 0x%x extends beyond resource end %p.",
+ name, size, (void*)(dataEnd-((const uint8_t*)chunk)));
return BAD_TYPE;
}
ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
name, (int)size, (int)headerSize);
return BAD_TYPE;
}
- ALOGW("%s size %p is smaller than header size %p.",
- name, (void*)size, (void*)(int)headerSize);
+ ALOGW("%s size 0x%x is smaller than header size 0x%x.",
+ name, size, headerSize);
return BAD_TYPE;
}
- ALOGW("%s header size %p is too small.",
- name, (void*)(int)headerSize);
+ ALOGW("%s header size 0x%x is too small.",
+ name, headerSize);
return BAD_TYPE;
}
@@ -279,11 +278,37 @@
if (!assertIdmapHeader(map, mapSize)) {
return UNKNOWN_ERROR;
}
+ if (mapSize <= IDMAP_HEADER_SIZE + 1) {
+ ALOGW("corrupt idmap: map size %d too short\n", mapSize);
+ return UNKNOWN_ERROR;
+ }
+ uint32_t typeCount = *(map + IDMAP_HEADER_SIZE);
+ if (typeCount == 0) {
+ ALOGW("corrupt idmap: no types\n");
+ return UNKNOWN_ERROR;
+ }
+ if (IDMAP_HEADER_SIZE + 1 + typeCount > mapSize) {
+ ALOGW("corrupt idmap: number of types %d extends past idmap size %d\n", typeCount, mapSize);
+ return UNKNOWN_ERROR;
+ }
const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
+ // find first defined type
while (*p == 0) {
++p;
+ if (--typeCount == 0) {
+ ALOGW("corrupt idmap: types declared, none found\n");
+ return UNKNOWN_ERROR;
+ }
}
- *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
+
+ // determine package id from first entry of first type
+ const uint32_t offset = *p + IDMAP_HEADER_SIZE + 2;
+ if (offset > mapSize) {
+ ALOGW("corrupt idmap: entry offset %d points outside map size %d\n", offset, mapSize);
+ return UNKNOWN_ERROR;
+ }
+ *outId = (map[offset] >> 24) & 0x000000ff;
+
return NO_ERROR;
}
@@ -3226,8 +3251,8 @@
}
curPackage++;
} else {
- ALOGW("Unknown chunk type %p in table at %p.\n",
- (void*)(int)(ctype),
+ ALOGW("Unknown chunk type 0x%x in table at %p.\n",
+ ctype,
(void*)(((const uint8_t*)chunk) - ((const uint8_t*)header->header)));
}
chunk = (const ResChunk_header*)
@@ -3443,8 +3468,8 @@
if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) != 0) {
if (!mayBeBag) {
- ALOGW("Requesting resource %p failed because it is complex\n",
- (void*)resID);
+ ALOGW("Requesting resource 0x%x failed because it is complex\n",
+ resID);
}
continue;
}
@@ -3719,8 +3744,8 @@
}
if ((dtohs(entry->flags)&entry->FLAG_COMPLEX) == 0) {
- ALOGW("Skipping entry %p in package table %d because it is not complex!\n",
- (void*)resID, (int)ip);
+ ALOGW("Skipping entry 0x%x in package table %zu because it is not complex!\n",
+ resID, ip);
continue;
}
@@ -5316,26 +5341,26 @@
return (mError=err);
}
- const size_t pkgSize = dtohl(pkg->header.size);
+ const uint32_t pkgSize = dtohl(pkg->header.size);
if (dtohl(pkg->typeStrings) >= pkgSize) {
- ALOGW("ResTable_package type strings at %p are past chunk size %p.",
- (void*)dtohl(pkg->typeStrings), (void*)pkgSize);
+ ALOGW("ResTable_package type strings at 0x%x are past chunk size 0x%x.",
+ dtohl(pkg->typeStrings), pkgSize);
return (mError=BAD_TYPE);
}
if ((dtohl(pkg->typeStrings)&0x3) != 0) {
- ALOGW("ResTable_package type strings at %p is not on an integer boundary.",
- (void*)dtohl(pkg->typeStrings));
+ ALOGW("ResTable_package type strings at 0x%x is not on an integer boundary.",
+ dtohl(pkg->typeStrings));
return (mError=BAD_TYPE);
}
if (dtohl(pkg->keyStrings) >= pkgSize) {
- ALOGW("ResTable_package key strings at %p are past chunk size %p.",
- (void*)dtohl(pkg->keyStrings), (void*)pkgSize);
+ ALOGW("ResTable_package key strings at 0x%x are past chunk size 0x%x.",
+ dtohl(pkg->keyStrings), pkgSize);
return (mError=BAD_TYPE);
}
if ((dtohl(pkg->keyStrings)&0x3) != 0) {
- ALOGW("ResTable_package key strings at %p is not on an integer boundary.",
- (void*)dtohl(pkg->keyStrings));
+ ALOGW("ResTable_package key strings at 0x%x is not on an integer boundary.",
+ dtohl(pkg->keyStrings));
return (mError=BAD_TYPE);
}
@@ -5473,7 +5498,7 @@
return (mError=err);
}
- const size_t typeSize = dtohl(type->header.size);
+ const uint32_t typeSize = dtohl(type->header.size);
LOAD_TABLE_NOISY(printf("Type off %p: type=0x%x, headerSize=0x%x, size=%p\n",
(void*)(base-(const uint8_t*)chunk),
@@ -5482,16 +5507,16 @@
(void*)typeSize));
if (dtohs(type->header.headerSize)+(sizeof(uint32_t)*dtohl(type->entryCount))
> typeSize) {
- ALOGW("ResTable_type entry index to %p extends beyond chunk end %p.",
+ ALOGW("ResTable_type entry index to %p extends beyond chunk end 0x%x.",
(void*)(dtohs(type->header.headerSize)
+(sizeof(uint32_t)*dtohl(type->entryCount))),
- (void*)typeSize);
+ typeSize);
return (mError=BAD_TYPE);
}
if (dtohl(type->entryCount) != 0
&& dtohl(type->entriesStart) > (typeSize-sizeof(ResTable_entry))) {
- ALOGW("ResTable_type entriesStart at %p extends beyond chunk end %p.",
- (void*)dtohl(type->entriesStart), (void*)typeSize);
+ ALOGW("ResTable_type entriesStart at 0x%x extends beyond chunk end 0x%x.",
+ dtohl(type->entriesStart), typeSize);
return (mError=BAD_TYPE);
}
if (type->id == 0) {
@@ -5536,23 +5561,30 @@
return NO_ERROR;
}
-status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
- void** outData, size_t* outSize) const
+status_t ResTable::createIdmap(const ResTable& overlay,
+ uint32_t targetCrc, uint32_t overlayCrc,
+ const char* targetPath, const char* overlayPath,
+ void** outData, size_t* outSize) const
{
// see README for details on the format of map
if (mPackageGroups.size() == 0) {
+ ALOGW("idmap: target package has no package groups, cannot create idmap\n");
return UNKNOWN_ERROR;
}
if (mPackageGroups[0]->packages.size() == 0) {
+ ALOGW("idmap: target package has no packages in its first package group, "
+ "cannot create idmap\n");
return UNKNOWN_ERROR;
}
Vector<Vector<uint32_t> > map;
+ // overlaid packages are assumed to contain only one package group
const PackageGroup* pg = mPackageGroups[0];
const Package* pkg = pg->packages[0];
size_t typeCount = pkg->types.size();
// starting size is header + first item (number of types in map)
*outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
+ // overlay packages are assumed to contain only one package group
const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
const uint32_t pkg_id = pkg->package->id << 24;
@@ -5628,8 +5660,22 @@
}
uint32_t* data = (uint32_t*)*outData;
*data++ = htodl(IDMAP_MAGIC);
- *data++ = htodl(originalCrc);
+ *data++ = htodl(targetCrc);
*data++ = htodl(overlayCrc);
+ const char* paths[] = { targetPath, overlayPath };
+ for (int j = 0; j < 2; ++j) {
+ char* p = (char*)data;
+ const char* path = paths[j];
+ const size_t I = strlen(path);
+ if (I > 255) {
+ ALOGV("path exceeds expected 255 characters: %s\n", path);
+ return UNKNOWN_ERROR;
+ }
+ for (size_t i = 0; i < 256; ++i) {
+ *p++ = i < I ? path[i] : '\0';
+ }
+ data += 256 / sizeof(uint32_t);
+ }
const size_t mapSize = map.size();
*data++ = htodl(mapSize);
size_t offset = mapSize;
@@ -5644,6 +5690,10 @@
offset += N;
}
}
+ if (offset == mapSize) {
+ ALOGW("idmap: no resources in overlay package present in base package\n");
+ return UNKNOWN_ERROR;
+ }
for (size_t i = 0; i < mapSize; ++i) {
const Vector<uint32_t>& vector = map.itemAt(i);
const size_t N = vector.size();
@@ -5665,14 +5715,25 @@
}
bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
- uint32_t* pOriginalCrc, uint32_t* pOverlayCrc)
+ uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
+ String8* pTargetPath, String8* pOverlayPath)
{
const uint32_t* map = (const uint32_t*)idmap;
if (!assertIdmapHeader(map, sizeBytes)) {
return false;
}
- *pOriginalCrc = map[1];
- *pOverlayCrc = map[2];
+ if (pTargetCrc) {
+ *pTargetCrc = map[1];
+ }
+ if (pOverlayCrc) {
+ *pOverlayCrc = map[2];
+ }
+ if (pTargetPath) {
+ pTargetPath->setTo(reinterpret_cast<const char*>(map + 3));
+ }
+ if (pOverlayPath) {
+ pOverlayPath->setTo(reinterpret_cast<const char*>(map + 3 + 256 / sizeof(uint32_t)));
+ }
return true;
}
@@ -5872,12 +5933,12 @@
size_t entryCount = dtohl(type->entryCount);
uint32_t entriesStart = dtohl(type->entriesStart);
if ((entriesStart&0x3) != 0) {
- printf(" NON-INTEGER ResTable_type entriesStart OFFSET: %p\n", (void*)entriesStart);
+ printf(" NON-INTEGER ResTable_type entriesStart OFFSET: 0x%x\n", entriesStart);
continue;
}
uint32_t typeSize = dtohl(type->header.size);
if ((typeSize&0x3) != 0) {
- printf(" NON-INTEGER ResTable_type header.size: %p\n", (void*)typeSize);
+ printf(" NON-INTEGER ResTable_type header.size: 0x%x\n", typeSize);
continue;
}
for (size_t entryIndex=0; entryIndex<entryCount; entryIndex++) {
@@ -5916,33 +5977,31 @@
printf(" INVALID RESOURCE 0x%08x: ", resID);
}
if ((thisOffset&0x3) != 0) {
- printf("NON-INTEGER OFFSET: %p\n", (void*)thisOffset);
+ printf("NON-INTEGER OFFSET: 0x%x\n", thisOffset);
continue;
}
if ((thisOffset+sizeof(ResTable_entry)) > typeSize) {
- printf("OFFSET OUT OF BOUNDS: %p+%p (size is %p)\n",
- (void*)entriesStart, (void*)thisOffset,
- (void*)typeSize);
+ printf("OFFSET OUT OF BOUNDS: 0x%x+0x%x (size is 0x%x)\n",
+ entriesStart, thisOffset, typeSize);
continue;
}
const ResTable_entry* ent = (const ResTable_entry*)
(((const uint8_t*)type) + entriesStart + thisOffset);
if (((entriesStart + thisOffset)&0x3) != 0) {
- printf("NON-INTEGER ResTable_entry OFFSET: %p\n",
- (void*)(entriesStart + thisOffset));
+ printf("NON-INTEGER ResTable_entry OFFSET: 0x%x\n",
+ (entriesStart + thisOffset));
continue;
}
uintptr_t esize = dtohs(ent->size);
if ((esize&0x3) != 0) {
- printf("NON-INTEGER ResTable_entry SIZE: %p\n", (void*)esize);
+ printf("NON-INTEGER ResTable_entry SIZE: 0x%x\n", esize);
continue;
}
if ((thisOffset+esize) > typeSize) {
- printf("ResTable_entry OUT OF BOUNDS: %p+%p+%p (size is %p)\n",
- (void*)entriesStart, (void*)thisOffset,
- (void*)esize, (void*)typeSize);
+ printf("ResTable_entry OUT OF BOUNDS: 0x%x+0x%x+0x%x (size is 0x%x)\n",
+ entriesStart, thisOffset, esize, typeSize);
continue;
}
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index fddfe90..fc86e4f 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -28,7 +28,7 @@
// Lifecycle
///////////////////////////////////////////////////////////////////////////////
-void AssetAtlas::init(sp<GraphicBuffer> buffer, int* map, int count) {
+void AssetAtlas::init(sp<GraphicBuffer> buffer, int64_t* map, int count) {
if (mImage) {
return;
}
@@ -108,14 +108,19 @@
/**
* TODO: This method does not take the rotation flag into account
*/
-void AssetAtlas::createEntries(Caches& caches, int* map, int count) {
+void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) {
const float width = float(mTexture->width);
const float height = float(mTexture->height);
for (int i = 0; i < count; ) {
- SkBitmap* bitmap = (SkBitmap*) map[i++];
- int x = map[i++];
- int y = map[i++];
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(map[i++]);
+ // NOTE: We're converting from 64 bit signed values to 32 bit
+ // signed values. This is guaranteed to be safe because the "x"
+ // and "y" coordinate values are guaranteed to be representable
+ // with 32 bits. The array is 64 bits wide so that it can carry
+ // pointers on 64 bit architectures.
+ const int x = static_cast<int>(map[i++]);
+ const int y = static_cast<int>(map[i++]);
bool rotated = map[i++] > 0;
// Bitmaps should never be null, we're just extra paranoid
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
index 57c8a60..2ec556e 100644
--- a/libs/hwui/AssetAtlas.h
+++ b/libs/hwui/AssetAtlas.h
@@ -121,7 +121,7 @@
* initialized. To re-initialize the atlas, you must
* first call terminate().
*/
- ANDROID_API void init(sp<GraphicBuffer> buffer, int* map, int count);
+ ANDROID_API void init(sp<GraphicBuffer> buffer, int64_t* map, int count);
/**
* Destroys the atlas texture. This object can be
@@ -176,7 +176,7 @@
}
private:
- void createEntries(Caches& caches, int* map, int count);
+ void createEntries(Caches& caches, int64_t* map, int count);
Texture* mTexture;
Image* mImage;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 8bd9de0..21cf658 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -685,7 +685,8 @@
propertyDirtyViewport = false;
propertyEnable3d = false;
propertyCameraDistance = 1.0f;
- propertyShadowStrength = 0x3f;
+ propertyAmbientShadowStrength = 0x3f;
+ propertySpotShadowStrength = 0x3f;
propertyLightPosXScale = 0.5f;
propertyLightPosYScale = 0.0f;
@@ -704,9 +705,13 @@
propertyDirtyViewport = true;
ALOGD("camera dist multiplier = %.2f", propertyCameraDistance);
return;
- } else if (!strcmp(name, "shadowStrength")) {
- propertyShadowStrength = atoi(value);
- ALOGD("shadow strength = 0x%x out of 0xff", propertyShadowStrength);
+ } else if (!strcmp(name, "ambientShadowStrength")) {
+ propertyAmbientShadowStrength = atoi(value);
+ ALOGD("ambient shadow strength = 0x%x out of 0xff", propertyAmbientShadowStrength);
+ return;
+ } else if (!strcmp(name, "spotShadowStrength")) {
+ propertySpotShadowStrength = atoi(value);
+ ALOGD("spot shadow strength = 0x%x out of 0xff", propertySpotShadowStrength);
return;
} else if (!strcmp(name, "lightPosXScale")) {
propertyLightPosXScale = fmin(fmax(atof(value), 0.0), 1.0);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e7ba9ac..2cc15cc 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -367,7 +367,8 @@
float propertyLightPosXScale;
float propertyLightPosYScale;
float propertyLightPosZScale;
- int propertyShadowStrength;
+ int propertyAmbientShadowStrength;
+ int propertySpotShadowStrength;
private:
enum OverdrawColorSet {
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index ed05d04..62f6c76 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -31,25 +31,26 @@
, mLayer(layer)
, mRenderer(renderer)
, mCaches(Caches::getInstance()) {
- mCaches.resourceCache.incrementRefcount(mLayer);
mWidth = mLayer->layer.getWidth();
mHeight = mLayer->layer.getHeight();
mBlend = mLayer->isBlend();
- mColorFilter = mLayer->getColorFilter();
+ mColorFilter = SkSafeRef(mLayer->getColorFilter());
mAlpha = mLayer->getAlpha();
mMode = mLayer->getMode();
mDirtyRect.setEmpty();
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
- setColorFilter(NULL);
+ SkSafeUnref(mColorFilter);
if (mLayer) {
mCaches.resourceCache.decrementRefcount(mLayer);
}
delete mRenderer;
}
-void DeferredLayerUpdater::setColorFilter(SkColorFilter* colorFilter) {
+void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
+ OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
+ SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : NULL;
SkRefCnt_SafeAssign(mColorFilter, colorFilter);
}
@@ -124,27 +125,5 @@
}
}
-void DeferredLayerUpdater::applyDeferred(DeferredLayerUpdater* deferredApply) {
- // Default assignment operator doesn't quite work, and fails due to mCaches anyway
- deferredApply->mWidth = mWidth;
- deferredApply->mHeight = mHeight;
- deferredApply->mBlend = mBlend;
- deferredApply->mAlpha = mAlpha;
- deferredApply->mMode = mMode;
- deferredApply->mDirtyRect.set(mDirtyRect);
- deferredApply->mDisplayList = mDisplayList;
- deferredApply->mSurfaceTexture = mSurfaceTexture;
- deferredApply->mNeedsGLContextAttach = mNeedsGLContextAttach;
- deferredApply->mUpdateTexImage = mUpdateTexImage;
- deferredApply->setColorFilter(mColorFilter);
- deferredApply->setTransform(mTransform);
-
- mDisplayList = 0;
- mDirtyRect.setEmpty();
- mTransform = 0;
- mNeedsGLContextAttach = false;
- mUpdateTexImage = false;
-}
-
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 0350eef..65f225c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -34,6 +34,8 @@
// of a render pass
class DeferredLayerUpdater {
public:
+ // Note that DeferredLayerUpdater assumes it is taking ownership of the layer
+ // and will not call incrementRef on it as a result.
ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
ANDROID_API ~DeferredLayerUpdater();
@@ -73,14 +75,9 @@
ANDROID_API void setDisplayList(DisplayList* displayList,
int left, int top, int right, int bottom);
- ANDROID_API void setPaint(const SkPaint* paint) {
- OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
- }
-
- ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
+ ANDROID_API void setPaint(const SkPaint* paint);
ANDROID_API bool apply();
- ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
ANDROID_API Layer* backingLayer() {
return mLayer;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index a5e66fa..23c33ca 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -232,7 +232,7 @@
mOutline.rewind();
mClipToOutline = false;
mCastsShadow = false;
- mSharesGlobalCamera = false;
+ mUsesGlobalCamera = false;
mAlpha = 1;
mHasOverlappingRendering = true;
mTranslationX = 0;
@@ -661,7 +661,8 @@
if (mode == kNegativeZChildren && zValue > 0.0f) break;
DisplayList* child = childOp->mDisplayList;
- if (mode == kPositiveZChildren && zValue > 0.0f && child->mCastsShadow) {
+ if (mode == kPositiveZChildren && zValue > 0.0f
+ && child->mCastsShadow && child->mAlpha > 0.0f) {
/* draw shadow with parent matrix applied, passing in the child's total matrix
* TODO: consider depth in more complex scenarios (neg z, added shadow depth)
*/
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index c3d9fd7..9487fae 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -196,8 +196,8 @@
mCastsShadow = castsShadow;
}
- void setSharesGlobalCamera(bool sharesGlobalCamera) {
- mSharesGlobalCamera = sharesGlobalCamera;
+ void setUsesGlobalCamera(bool usesGlobalCamera) {
+ mUsesGlobalCamera = usesGlobalCamera;
}
void setProjectBackwards(bool shouldProject) {
@@ -621,7 +621,7 @@
SkPath mOutline;
bool mClipToOutline;
bool mCastsShadow;
- bool mSharesGlobalCamera; // TODO: respect value when rendering
+ bool mUsesGlobalCamera; // TODO: respect value when rendering
float mAlpha;
bool mHasOverlappingRendering;
float mTranslationX, mTranslationY, mTranslationZ;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 0589a02..b5a66f6 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1410,7 +1410,7 @@
DeferredDisplayList::kOpBatch_Text :
DeferredDisplayList::kOpBatch_ColorText;
- deferInfo.mergeId = (mergeid_t)mPaint->getColor();
+ deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor());
// don't merge decorated text - the decorations won't draw in order
bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 70eeb39..54ce64f 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -131,8 +131,9 @@
}
}
-void Layer::setPaint(SkPaint* paint) {
+void Layer::setPaint(const SkPaint* paint) {
OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+ setColorFilter((paint) ? paint->getColorFilter() : NULL);
}
void Layer::setColorFilter(SkColorFilter* filter) {
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index ec80e9c..8cc027a 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -117,7 +117,7 @@
texture.height = height;
}
- ANDROID_API void setPaint(SkPaint* paint);
+ ANDROID_API void setPaint(const SkPaint* paint);
inline void setBlend(bool blend) {
texture.blend = blend;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index fee916b..75bf716 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -868,14 +868,11 @@
const bool fboLayer = flags & SkCanvas::kClipToLayer_SaveFlag;
- SkXfermode::Mode mode = getXfermodeDirect(paint);
- int alpha = getAlphaDirect(paint);
-
// Window coordinates of the layer
Rect clip;
Rect bounds(left, top, right, bottom);
calculateLayerBoundsAndClip(bounds, clip, fboLayer);
- updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, alpha);
+ updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
// Bail out if we won't draw in this snapshot
if (currentSnapshot()->isIgnored()) {
@@ -888,12 +885,11 @@
return false;
}
- layer->setAlpha(alpha, mode);
+ layer->setPaint(paint);
layer->layer.set(bounds);
layer->texCoords.set(0.0f, bounds.getHeight() / float(layer->getHeight()),
bounds.getWidth() / float(layer->getWidth()), 0.0f);
- layer->setColorFilter(getColorFilter(paint));
layer->setBlend(true);
layer->setDirty(false);
@@ -1011,7 +1007,6 @@
}
if (!fboLayer && layer->getAlpha() < 255) {
- // TODO: this seems to point to the fact that the layer should store the paint
SkPaint layerPaint;
layerPaint.setAlpha(layer->getAlpha());
layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode);
@@ -3214,7 +3209,6 @@
mCaches.enableScissor();
SkPaint paint;
- paint.setARGB(mCaches.propertyShadowStrength, 0, 0, 0);
paint.setAntiAlias(true); // want to use AlphaVertex
// tessellate caster outline into a 2d polygon
@@ -3238,19 +3232,25 @@
}
// draw caster's shadows
- VertexBuffer ambientShadowVertexBuffer;
- ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
- ambientShadowVertexBuffer);
- drawVertexBuffer(ambientShadowVertexBuffer, &paint);
+ if (mCaches.propertyAmbientShadowStrength > 0) {
+ paint.setARGB(casterAlpha * mCaches.propertyAmbientShadowStrength, 0, 0, 0);
+ VertexBuffer ambientShadowVertexBuffer;
+ ShadowTessellator::tessellateAmbientShadow(casterPolygon, casterVertexCount,
+ ambientShadowVertexBuffer);
+ drawVertexBuffer(ambientShadowVertexBuffer, &paint);
+ }
- VertexBuffer spotShadowVertexBuffer;
- Vector3 lightPosScale(mCaches.propertyLightPosXScale,
- mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
- ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount,
- lightPosScale, *currentTransform(), getWidth(), getHeight(),
- spotShadowVertexBuffer);
+ if (mCaches.propertySpotShadowStrength > 0) {
+ paint.setARGB(casterAlpha * mCaches.propertySpotShadowStrength, 0, 0, 0);
+ VertexBuffer spotShadowVertexBuffer;
+ Vector3 lightPosScale(mCaches.propertyLightPosXScale,
+ mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
+ ShadowTessellator::tessellateSpotShadow(casterPolygon, casterVertexCount,
+ lightPosScale, *currentTransform(), getWidth(), getHeight(),
+ spotShadowVertexBuffer);
- drawVertexBuffer(spotShadowVertexBuffer, &paint);
+ drawVertexBuffer(spotShadowVertexBuffer, &paint);
+ }
return DrawGlInfo::kStatusDrew;
}
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 36e89c6..5b642b9 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -151,7 +151,7 @@
mCaches.bindPixelBuffer(mBuffer);
unmap();
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
- GL_UNSIGNED_BYTE, (void*) offset);
+ GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4e665d9..fe781bd 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -24,6 +24,8 @@
#include "RenderThread.h"
#include "../Caches.h"
+#include "../DeferredLayerUpdater.h"
+#include "../LayerRenderer.h"
#include "../OpenGLRenderer.h"
#include "../Stencil.h"
@@ -371,6 +373,17 @@
mCanvas->setViewport(width, height);
}
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
+ mGlobalContext->makeCurrent(mEglSurface);
+ for (size_t i = 0; i < layerUpdaters->size(); i++) {
+ DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
+ LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!");
+ if (update->backingLayer()->deferredUpdateScheduled) {
+ mCanvas->pushLayerUpdate(update->backingLayer());
+ }
+ }
+}
+
void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) {
LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
"drawDisplayList called on a context with no canvas or surface!");
@@ -462,14 +475,23 @@
mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
}
+bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+ requireGlContext();
+ layer->apply();
+ return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
+}
+
void CanvasContext::runWithGlContext(RenderTask* task) {
+ requireGlContext();
+ task->run();
+}
+
+void CanvasContext::requireGlContext() {
if (mEglSurface != EGL_NO_SURFACE) {
mGlobalContext->makeCurrent(mEglSurface);
} else {
mGlobalContext->usePBufferSurface();
}
-
- task->run();
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3197df3..5fac582 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -19,7 +19,9 @@
#include <cutils/compiler.h>
#include <EGL/egl.h>
+#include <SkBitmap.h>
#include <utils/Functor.h>
+#include <utils/Vector.h>
#include "RenderTask.h"
@@ -28,6 +30,7 @@
namespace android {
namespace uirenderer {
+class DeferredLayerUpdater;
class DisplayList;
class OpenGLRenderer;
class Rect;
@@ -59,9 +62,12 @@
bool initialize(EGLNativeWindowType window);
void updateSurface(EGLNativeWindowType window);
void setup(int width, int height);
+ void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
void drawDisplayList(DisplayList* displayList, Rect* dirty);
void destroyCanvas();
+ bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+
void attachFunctor(Functor* functor);
void detachFunctor(Functor* functor);
@@ -78,6 +84,8 @@
void removeFunctorsTask();
void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
+ void requireGlContext();
+
GlobalContext* mGlobalContext;
RenderThread& mRenderThread;
EGLSurface mEglSurface;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 34f1961..0c667fd 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,7 +22,9 @@
#include "RenderTask.h"
#include "RenderThread.h"
+#include "../DeferredLayerUpdater.h"
#include "../DisplayList.h"
+#include "../LayerRenderer.h"
#include "../Rect.h"
namespace android {
@@ -31,6 +33,7 @@
#define ARGS(method) method ## Args
+#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,)
#define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
#define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
#define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
@@ -114,13 +117,14 @@
post(task);
}
-CREATE_BRIDGE3(drawDisplayList, CanvasContext* context, DisplayList* displayList,
- Rect dirty) {
+CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList,
+ Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) {
Rect* dirty = &args->dirty;
if (dirty->bottom == -1 && dirty->left == -1 &&
dirty->top == -1 && dirty->right == -1) {
dirty = 0;
}
+ args->context->processLayerUpdates(args->layerUpdates);
args->context->drawDisplayList(args->displayList, dirty);
return NULL;
}
@@ -131,6 +135,7 @@
args->context = mContext;
args->displayList = displayList;
args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+ args->layerUpdates = &mLayers;
// TODO: Switch to post() once some form of thread safety strategy is in place
postAndWait(task);
}
@@ -182,6 +187,70 @@
postAndWait(task);
}
+CREATE_BRIDGE2(createDisplayListLayer, int width, int height) {
+ Layer* layer = LayerRenderer::createRenderLayer(args->width, args->height);
+ if (!layer) return 0;
+
+ OpenGLRenderer* renderer = new LayerRenderer(layer);
+ renderer->initProperties();
+ return new DeferredLayerUpdater(layer, renderer);
+}
+
+DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
+ SETUP_TASK(createDisplayListLayer);
+ args->width = width;
+ args->height = height;
+ void* retval = postAndWait(task);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+ mLayers.push(layer);
+ return layer;
+}
+
+CREATE_BRIDGE0(createTextureLayer) {
+ Layer* layer = LayerRenderer::createTextureLayer();
+ if (!layer) return 0;
+ return new DeferredLayerUpdater(layer);
+}
+
+DeferredLayerUpdater* RenderProxy::createTextureLayer() {
+ SETUP_TASK(createTextureLayer);
+ void* retval = postAndWait(task);
+ DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+ mLayers.push(layer);
+ return layer;
+}
+
+CREATE_BRIDGE1(destroyLayer, Layer* layer) {
+ LayerRenderer::destroyLayer(args->layer);
+ return NULL;
+}
+
+CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
+ SkBitmap* bitmap) {
+ bool success = args->context->copyLayerInto(args->layer, args->bitmap);
+ return (void*) success;
+}
+
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+ SETUP_TASK(copyLayerInto);
+ args->context = mContext;
+ args->layer = layer;
+ args->bitmap = bitmap;
+ return (bool) postAndWait(task);
+}
+
+void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
+ for (size_t i = 0; i < mLayers.size(); i++) {
+ if (mLayers[i] == layer) {
+ mLayers.removeAt(i);
+ break;
+ }
+ }
+ SETUP_TASK(destroyLayer);
+ args->layer = layer->detachBackingLayer();
+ post(task);
+}
+
MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
// TODO: Consider having a small pool of these to avoid alloc churn
return new MethodInvokeRenderTask(method);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1ad0c2d..8ff3d63 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -21,15 +21,19 @@
#include <cutils/compiler.h>
#include <EGL/egl.h>
+#include <SkBitmap.h>
#include <utils/Condition.h>
#include <utils/Functor.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
namespace android {
namespace uirenderer {
+class DeferredLayerUpdater;
class DisplayList;
+class Layer;
class Rect;
namespace renderthread {
@@ -64,6 +68,11 @@
ANDROID_API void runWithGlContext(RenderTask* task);
+ ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
+ ANDROID_API DeferredLayerUpdater* createTextureLayer();
+ ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+ ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
@@ -71,6 +80,8 @@
Mutex mSyncMutex;
Condition mSyncCondition;
+ Vector<DeferredLayerUpdater*> mLayers;
+
void destroyContext();
MethodInvokeRenderTask* createTask(RunnableMethod method);
diff --git a/media/java/android/media/IMediaController.aidl b/media/java/android/media/IMediaController.aidl
new file mode 100644
index 0000000..fc3525a
--- /dev/null
+++ b/media/java/android/media/IMediaController.aidl
@@ -0,0 +1,34 @@
+/* Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Intent;
+import android.media.IMediaControllerCallback;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.KeyEvent;
+
+/**
+ * Interface to a MediaSession in the system.
+ * @hide
+ */
+interface IMediaController {
+ void sendCommand(String command, in Bundle extras);
+ void sendMediaButton(in KeyEvent mediaButton);
+ void registerCallbackListener(in IMediaControllerCallback cb);
+ void unregisterCallbackListener(in IMediaControllerCallback cb);
+ int getPlaybackState();
+}
\ No newline at end of file
diff --git a/media/java/android/media/IMediaControllerCallback.aidl b/media/java/android/media/IMediaControllerCallback.aidl
new file mode 100644
index 0000000..b54d0cf
--- /dev/null
+++ b/media/java/android/media/IMediaControllerCallback.aidl
@@ -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.
+ */
+
+package android.media;
+
+import android.os.Bundle;
+
+/**
+ * @hide
+ */
+oneway interface IMediaControllerCallback {
+ void onEvent(String event, in Bundle extras);
+ void onMetadataUpdate(in Bundle metadata);
+ void onPlaybackUpdate(int newState);
+ void onRouteChanged(in Bundle route);
+}
\ No newline at end of file
diff --git a/media/java/android/media/IMediaHTTPConnection.aidl b/media/java/android/media/IMediaHTTPConnection.aidl
index 300211b..55ffc2e 100644
--- a/media/java/android/media/IMediaHTTPConnection.aidl
+++ b/media/java/android/media/IMediaHTTPConnection.aidl
@@ -29,5 +29,6 @@
int readAt(long offset, int size);
long getSize();
String getMIMEType();
+ String getUri();
}
diff --git a/media/java/android/media/IMediaSession.aidl b/media/java/android/media/IMediaSession.aidl
new file mode 100644
index 0000000..ed71d78
--- /dev/null
+++ b/media/java/android/media/IMediaSession.aidl
@@ -0,0 +1,33 @@
+/* Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.IMediaController;
+import android.os.Bundle;
+
+/**
+ * Interface to a MediaSession in the system.
+ * @hide
+ */
+interface IMediaSession {
+ void sendEvent(in Bundle data);
+ IMediaController getMediaSessionToken();
+ void setPlaybackState(int state);
+ void setMetadata(in Bundle metadata);
+ void setRouteState(in Bundle routeState);
+ void setRoute(in Bundle mediaRouteDescriptor);
+ void destroy();
+}
\ No newline at end of file
diff --git a/media/java/android/media/IMediaSessionCallback.aidl b/media/java/android/media/IMediaSessionCallback.aidl
new file mode 100644
index 0000000..3aaf925
--- /dev/null
+++ b/media/java/android/media/IMediaSessionCallback.aidl
@@ -0,0 +1,29 @@
+/* Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * @hide
+ */
+oneway interface IMediaSessionCallback {
+ void onCommand(String command, in Bundle extras);
+ void onMediaButton(in Intent mediaRequestIntent);
+ void onRequestRouteChange(in Bundle route);
+}
\ No newline at end of file
diff --git a/media/java/android/media/IMediaSessionManager.aidl b/media/java/android/media/IMediaSessionManager.aidl
new file mode 100644
index 0000000..8bc0c3b
--- /dev/null
+++ b/media/java/android/media/IMediaSessionManager.aidl
@@ -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.
+ */
+
+package android.media;
+
+import android.media.IMediaSession;
+import android.media.IMediaSessionCallback;
+import android.os.Bundle;
+
+/**
+ * Interface to the MediaSessionManagerService
+ * @hide
+ */
+interface IMediaSessionManager {
+ IMediaSession createSession(String packageName, in IMediaSessionCallback cb, String tag);
+}
\ No newline at end of file
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 9fe3ac1..115786c 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -333,6 +333,10 @@
* <p>
* The application is responsible for calling release() on the Surface when
* done.
+ * <p>
+ * The Surface must be rendered with a hardware-accelerated API, such as OpenGL ES.
+ * {@link android.view.Surface#lockCanvas(android.graphics.Rect)} may fail or produce
+ * unexpected results.
*/
public native final Surface createInputSurface();
diff --git a/media/java/android/media/MediaController.java b/media/java/android/media/MediaController.java
new file mode 100644
index 0000000..1e99942
--- /dev/null
+++ b/media/java/android/media/MediaController.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+
+/**
+ * Allows an app to interact with an ongoing media session. Media buttons and
+ * other commands can be sent to the session. A callback may be registered to
+ * receive updates from the session, such as metadata and play state changes.
+ * <p>
+ * A MediaController can be created through {@link MediaSessionManager} if you
+ * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or directly if
+ * you have a {@link MediaSessionToken} from the session owner.
+ * <p>
+ * MediaController objects are thread-safe.
+ */
+public final class MediaController {
+ private static final String TAG = "MediaController";
+
+ private static final int MESSAGE_EVENT = 1;
+ private static final int MESSAGE_PLAYBACK_STATE = 2;
+ private static final int MESSAGE_METADATA = 3;
+ private static final int MESSAGE_ROUTE = 4;
+
+ private static final String KEY_EVENT = "event";
+ private static final String KEY_EXTRAS = "extras";
+
+ private final IMediaController mSessionBinder;
+
+ private final CallbackStub mCbStub = new CallbackStub();
+ private final ArrayList<Callback> mCbs = new ArrayList<Callback>();
+ private final Object mLock = new Object();
+
+ private boolean mCbRegistered = false;
+
+ /**
+ * If you have a {@link MediaSessionToken} from the owner of the session a
+ * controller can be created directly. It is up to the session creator to
+ * handle token distribution if desired.
+ *
+ * @see MediaSession#getSessionToken()
+ * @param token A token from the creator of the session
+ */
+ public MediaController(MediaSessionToken token) {
+ mSessionBinder = token.getBinder();
+ }
+
+ /**
+ * @hide
+ */
+ public MediaController(IMediaController sessionBinder) {
+ mSessionBinder = sessionBinder;
+ }
+
+ /**
+ * Sends a generic command to the session. It is up to the session creator
+ * to decide what commands and parameters they will support. As such,
+ * commands should only be sent to sessions that the controller owns.
+ *
+ * @param command The command to send
+ * @param params Any parameters to include with the command
+ */
+ public void sendCommand(String command, Bundle params) {
+ if (TextUtils.isEmpty(command)) {
+ throw new IllegalArgumentException("command cannot be null or empty");
+ }
+ try {
+ mSessionBinder.sendCommand(command, params);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Dead object in sendCommand.", e);
+ }
+ }
+
+ /**
+ * Send the specified media button to the session. Only media keys can be
+ * sent using this method.
+ *
+ * @param keycode The media button keycode, such as
+ * {@link KeyEvent#KEYCODE_MEDIA_PLAY}.
+ */
+ public void sendMediaButton(int keycode) {
+ if (!KeyEvent.isMediaKey(keycode)) {
+ throw new IllegalArgumentException("May only send media buttons through "
+ + "sendMediaButton");
+ }
+ // TODO do something better than key down/up events
+ KeyEvent event = new KeyEvent(KeyEvent.ACTION_UP, keycode);
+ try {
+ mSessionBinder.sendMediaButton(event);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Dead object in sendMediaButton", e);
+ }
+ }
+
+ /**
+ * Adds a callback to receive updates from the Session. Updates will be
+ * posted on the caller's thread.
+ *
+ * @param cb The callback object, must not be null
+ */
+ public void addCallback(Callback cb) {
+ addCallback(cb, null);
+ }
+
+ /**
+ * Adds a callback to receive updates from the session. Updates will be
+ * posted on the specified handler.
+ *
+ * @param cb Cannot be null.
+ * @param handler The handler to post updates on, if null the callers thread
+ * will be used
+ */
+ public void addCallback(Callback cb, Handler handler) {
+ if (handler == null) {
+ handler = new Handler();
+ }
+ synchronized (mLock) {
+ addCallbackLocked(cb, handler);
+ }
+ }
+
+ /**
+ * Stop receiving updates on the specified callback. If an update has
+ * already been posted you may still receive it after calling this method.
+ *
+ * @param cb The callback to remove
+ */
+ public void removeCallback(Callback cb) {
+ synchronized (mLock) {
+ removeCallbackLocked(cb);
+ }
+ }
+
+ /*
+ * @hide
+ */
+ IMediaController getSessionBinder() {
+ return mSessionBinder;
+ }
+
+ private void addCallbackLocked(Callback cb, Handler handler) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Callback cannot be null");
+ }
+ if (handler == null) {
+ throw new IllegalArgumentException("Handler cannot be null");
+ }
+ if (mCbs.contains(cb)) {
+ Log.w(TAG, "Callback is already added, ignoring");
+ return;
+ }
+ cb.setHandler(handler);
+ mCbs.add(cb);
+
+ // Only register one cb binder, track callbacks internally and notify
+ if (!mCbRegistered) {
+ try {
+ mSessionBinder.registerCallbackListener(mCbStub);
+ mCbRegistered = true;
+ } catch (RemoteException e) {
+ Log.d(TAG, "Dead object in registerCallback", e);
+ }
+ }
+ }
+
+ private void removeCallbackLocked(Callback cb) {
+ if (cb == null) {
+ throw new IllegalArgumentException("Callback cannot be null");
+ }
+ mCbs.remove(cb);
+
+ if (mCbs.size() == 0 && mCbRegistered) {
+ try {
+ mSessionBinder.unregisterCallbackListener(mCbStub);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Dead object in unregisterCallback", e);
+ }
+ mCbRegistered = false;
+ }
+ }
+
+ private void pushOnEventLocked(String event, Bundle extras) {
+ for (int i = mCbs.size() - 1; i >= 0; i--) {
+ mCbs.get(i).postEvent(event, extras);
+ }
+ }
+
+ private void pushOnMetadataUpdateLocked(Bundle metadata) {
+ for (int i = mCbs.size() - 1; i >= 0; i--) {
+ mCbs.get(i).postMetadataUpdate(metadata);
+ }
+ }
+
+ private void pushOnPlaybackUpdateLocked(int newState) {
+ for (int i = mCbs.size() - 1; i >= 0; i--) {
+ mCbs.get(i).postPlaybackStateChange(newState);
+ }
+ }
+
+ private void pushOnRouteChangedLocked(Bundle routeDescriptor) {
+ for (int i = mCbs.size() - 1; i >= 0; i--) {
+ mCbs.get(i).postRouteChanged(routeDescriptor);
+ }
+ }
+
+ /**
+ * MediaSession callbacks will be posted on the thread that created the
+ * Callback object.
+ */
+ public static abstract class Callback {
+ private Handler mHandler;
+
+ /**
+ * Override to handle custom events sent by the session owner.
+ * Controllers should only handle these for sessions they own.
+ *
+ * @param event
+ */
+ public void onEvent(String event, Bundle extras) {
+ }
+
+ /**
+ * Override to handle updates to the playback state. Valid values are in
+ * {@link RemoteControlClient}. TODO put playstate values somewhere more
+ * generic.
+ *
+ * @param state
+ */
+ public void onPlaybackStateChange(int state) {
+ }
+
+ /**
+ * Override to handle metadata changes for this session's media. The
+ * default supported fields are those in {@link MediaMetadataRetriever}.
+ *
+ * @param metadata
+ */
+ public void onMetadataUpdate(Bundle metadata) {
+ }
+
+ /**
+ * Override to handle route changes for this session.
+ *
+ * @param route
+ */
+ public void onRouteChanged(Bundle route) {
+ }
+
+ private void setHandler(Handler handler) {
+ mHandler = new MessageHandler(handler.getLooper(), this);
+ }
+
+ private void postEvent(String event, Bundle extras) {
+ Bundle eventBundle = new Bundle();
+ eventBundle.putString(KEY_EVENT, event);
+ eventBundle.putBundle(KEY_EXTRAS, extras);
+ Message msg = mHandler.obtainMessage(MESSAGE_EVENT, eventBundle);
+ mHandler.sendMessage(msg);
+ }
+
+ private void postPlaybackStateChange(final int state) {
+ Message msg = mHandler.obtainMessage(MESSAGE_PLAYBACK_STATE, state, 0);
+ mHandler.sendMessage(msg);
+ }
+
+ private void postMetadataUpdate(final Bundle metadata) {
+ Message msg = mHandler.obtainMessage(MESSAGE_METADATA, metadata);
+ mHandler.sendMessage(msg);
+ }
+
+ private void postRouteChanged(final Bundle descriptor) {
+ Message msg = mHandler.obtainMessage(MESSAGE_ROUTE, descriptor);
+ mHandler.sendMessage(msg);
+ }
+ }
+
+ private final class CallbackStub extends IMediaControllerCallback.Stub {
+
+ @Override
+ public void onEvent(String event, Bundle extras) throws RemoteException {
+ synchronized (mLock) {
+ pushOnEventLocked(event, extras);
+ }
+ }
+
+ @Override
+ public void onMetadataUpdate(Bundle metadata) throws RemoteException {
+ synchronized (mLock) {
+ pushOnMetadataUpdateLocked(metadata);
+ }
+ }
+
+ @Override
+ public void onPlaybackUpdate(final int newState) throws RemoteException {
+ synchronized (mLock) {
+ pushOnPlaybackUpdateLocked(newState);
+ }
+ }
+
+ @Override
+ public void onRouteChanged(Bundle mediaRouteDescriptor) throws RemoteException {
+ synchronized (mLock) {
+ pushOnRouteChangedLocked(mediaRouteDescriptor);
+ }
+ }
+
+ }
+
+ private final static class MessageHandler extends Handler {
+ private final MediaController.Callback mCb;
+
+ public MessageHandler(Looper looper, MediaController.Callback cb) {
+ super(looper);
+ mCb = cb;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_EVENT:
+ Bundle eventBundle = (Bundle) msg.obj;
+ String event = eventBundle.getString(KEY_EVENT);
+ Bundle extras = eventBundle.getBundle(KEY_EXTRAS);
+ mCb.onEvent(event, extras);
+ break;
+ case MESSAGE_PLAYBACK_STATE:
+ mCb.onPlaybackStateChange(msg.arg1);
+ break;
+ case MESSAGE_METADATA:
+ mCb.onMetadataUpdate((Bundle) msg.obj);
+ break;
+ case MESSAGE_ROUTE:
+ mCb.onRouteChanged((Bundle) msg.obj);
+ }
+ }
+ }
+
+}
diff --git a/media/java/android/media/MediaFocusControl.java b/media/java/android/media/MediaFocusControl.java
index 25ab99d..b155cda 100644
--- a/media/java/android/media/MediaFocusControl.java
+++ b/media/java/android/media/MediaFocusControl.java
@@ -262,7 +262,7 @@
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
final DisplayInfoForServer di =
- (DisplayInfoForServer) displayIterator.next();
+ displayIterator.next();
if (di.mClientNotifListComp != null) {
boolean wasEnabled = di.mEnabled;
di.mEnabled = isComponentInStringArray(di.mClientNotifListComp,
@@ -538,7 +538,7 @@
// evaluated it, traversal order doesn't matter here)
Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusRequester fr = (FocusRequester)stackIterator.next();
+ FocusRequester fr = stackIterator.next();
if(fr.hasSameClient(clientToRemove)) {
Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for "
+ clientToRemove);
@@ -562,7 +562,7 @@
// evaluated it, traversal order doesn't matter here)
Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
while(stackIterator.hasNext()) {
- FocusRequester fr = (FocusRequester)stackIterator.next();
+ FocusRequester fr = stackIterator.next();
if(fr.hasSameBinder(cb)) {
Log.i(TAG, "AudioFocus removeFocusStackEntry(): removing entry for " + cb);
stackIterator.remove();
@@ -930,33 +930,11 @@
}
}
- protected static boolean isMediaKeyCode(int keyCode) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- case KeyEvent.KEYCODE_MEDIA_CLOSE:
- case KeyEvent.KEYCODE_MEDIA_EJECT:
- case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
- return true;
- default:
- return false;
- }
- }
-
private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
if (keyEvent == null) {
return false;
}
- return MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode());
+ return KeyEvent.isMediaKey(keyEvent.getKeyCode());
}
/**
@@ -1383,7 +1361,7 @@
synchronized(mRCStack) {
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
pw.println(" IRCD: " + di.mRcDisplay +
" -- w:" + di.mArtworkExpectedWidth +
" -- h:" + di.mArtworkExpectedHeight +
@@ -1410,7 +1388,7 @@
// (using an iterator on the stack so we can safely remove an entry after having
// evaluated it, traversal order doesn't matter here)
while(stackIterator.hasNext()) {
- RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+ RemoteControlStackEntry rcse = stackIterator.next();
if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
// a stack entry is from the package being removed, remove it from the stack
stackIterator.remove();
@@ -2075,7 +2053,7 @@
// remove the display from the list
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
if (di.mRcDisplay == mRcDisplay) {
if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
displayIterator.remove();
@@ -2099,7 +2077,7 @@
private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
try {
rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
di.mArtworkExpectedHeight);
@@ -2137,7 +2115,7 @@
private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
return true;
}
@@ -2216,7 +2194,7 @@
boolean displayWasPluggedIn = false;
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext() && !displayWasPluggedIn) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
displayWasPluggedIn = true;
di.release();
@@ -2258,7 +2236,7 @@
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
boolean artworkSizeUpdate = false;
while (displayIterator.hasNext() && !artworkSizeUpdate) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
di.mArtworkExpectedWidth = w;
@@ -2305,7 +2283,7 @@
// (display stack traversal order doesn't matter).
final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
while (displayIterator.hasNext()) {
- final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
+ final DisplayInfoForServer di = displayIterator.next();
if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
di.mWantsPositionSync = wantsSync;
rcdRegistered = true;
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index 2732fbc..67680a8 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -16,7 +16,6 @@
package android.media;
-import android.net.Uri;
import android.os.IBinder;
import android.os.StrictMode;
import android.util.Log;
@@ -52,6 +51,7 @@
native_setup();
}
+ @Override
public IBinder connect(String uri, String headers) {
if (VERBOSE) {
Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
@@ -85,6 +85,7 @@
return map;
}
+ @Override
public void disconnect() {
teardownConnection();
mHeaders = null;
@@ -120,7 +121,11 @@
"Range", "bytes=" + offset + "-");
}
- if (mConnection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
+ int response = mConnection.getResponseCode();
+ // remember the current, possibly redirected URL
+ mURL = mConnection.getURL();
+
+ if (response == HttpURLConnection.HTTP_PARTIAL) {
// Partial content, we cannot just use getContentLength
// because what we want is not just the length of the range
// returned but the size of the full content if available.
@@ -145,16 +150,13 @@
}
}
}
- } else if (mConnection.getResponseCode()
- != HttpURLConnection.HTTP_OK) {
+ } else if (response != HttpURLConnection.HTTP_OK) {
throw new IOException();
} else {
mTotalSize = mConnection.getContentLength();
}
- if (offset > 0
- && mConnection.getResponseCode()
- != HttpURLConnection.HTTP_PARTIAL) {
+ if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
// Some servers simply ignore "Range" requests and serve
// data from the start of the content.
throw new IOException();
@@ -174,6 +176,7 @@
}
}
+ @Override
public int readAt(long offset, int size) {
return native_readAt(offset, size);
}
@@ -218,6 +221,7 @@
}
}
+ @Override
public long getSize() {
if (mConnection == null) {
try {
@@ -230,6 +234,7 @@
return mTotalSize;
}
+ @Override
public String getMIMEType() {
if (mConnection == null) {
try {
@@ -243,6 +248,11 @@
}
@Override
+ public String getUri() {
+ return mURL.toString();
+ }
+
+ @Override
protected void finalize() {
native_finalize();
}
@@ -260,4 +270,5 @@
}
private int mNativeContext;
+
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index f8a7bb6..21e2f4b 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -417,8 +417,8 @@
setParameter("time-lapse-enable=1");
double timeBetweenFrameCapture = 1 / fps;
- int timeBetweenFrameCaptureMs = (int) (1000 * timeBetweenFrameCapture);
- setParameter("time-between-time-lapse-frame-capture=" + timeBetweenFrameCaptureMs);
+ long timeBetweenFrameCaptureUs = (long) (1000000 * timeBetweenFrameCapture);
+ setParameter("time-between-time-lapse-frame-capture=" + timeBetweenFrameCaptureUs);
}
/**
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 01485b8..72f3e1a 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1426,7 +1426,7 @@
}
int firstSlash = path.lastIndexOf('/');
- if (firstSlash == 0) {
+ if (firstSlash <= 0) {
return false;
}
String parent = path.substring(0, firstSlash);
diff --git a/media/java/android/media/MediaSession.java b/media/java/android/media/MediaSession.java
new file mode 100644
index 0000000..5e5c9fa
--- /dev/null
+++ b/media/java/android/media/MediaSession.java
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Intent;
+import android.media.IMediaSession;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Allows interaction with media controllers, media routes, volume keys, media
+ * buttons, and transport controls.
+ * <p>
+ * A MediaSession should be created when an app wants to publish media playback
+ * information or negotiate with a media route. In general an app only needs one
+ * session for all playback, though multiple sessions can be created for sending
+ * media to multiple routes or to provide finer grain controls of media.
+ * <p>
+ * A MediaSession is created by calling
+ * {@link MediaSessionManager#createSession(String)}. Once a session is created
+ * apps that have the MEDIA_CONTENT_CONTROL permission can interact with the
+ * session through {@link MediaSessionManager#getActiveSessions()}. The owner of
+ * the session may also use {@link #getSessionToken()} to allow apps without
+ * this permission to create a {@link MediaController} to interact with this
+ * session.
+ * <p>
+ * To receive commands, media keys, and other events a Callback must be set with
+ * {@link #addCallback(Callback)}.
+ * <p>
+ * When an app is finished performing playback it must call {@link #release()}
+ * to clean up the session and notify any controllers.
+ * <p>
+ * MediaSession objects are thread safe
+ */
+public final class MediaSession {
+ private static final String TAG = "MediaSession";
+
+ private static final int MESSAGE_MEDIA_BUTTON = 1;
+ private static final int MESSAGE_COMMAND = 2;
+ private static final int MESSAGE_ROUTE_CHANGE = 3;
+
+ private static final String KEY_COMMAND = "command";
+ private static final String KEY_EXTRAS = "extras";
+
+ private final Object mLock = new Object();
+
+ private final MediaSessionToken mSessionToken;
+ private final IMediaSession mBinder;
+ private final CallbackStub mCbStub;
+
+ private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+
+ /**
+ * @hide
+ */
+ public MediaSession(IMediaSession binder, CallbackStub cbStub) {
+ mBinder = binder;
+ mCbStub = cbStub;
+ IMediaController controllerBinder = null;
+ try {
+ controllerBinder = mBinder.getMediaSessionToken();
+ } catch (RemoteException e) {
+ throw new RuntimeException("Dead object in MediaSessionController constructor: ", e);
+ }
+ mSessionToken = new MediaSessionToken(controllerBinder);
+ }
+
+ /**
+ * Set the callback to receive updates on.
+ *
+ * @param callback The callback object
+ */
+ public void addCallback(Callback callback) {
+ addCallback(callback, null);
+ }
+
+ public void addCallback(Callback callback, Handler handler) {
+ if (callback == null) {
+ throw new IllegalArgumentException("Callback cannot be null");
+ }
+ synchronized (mLock) {
+ if (mCallbacks.contains(callback)) {
+ Log.w(TAG, "Callback is already added, ignoring");
+ }
+ if (handler == null) {
+ handler = new Handler();
+ }
+ MessageHandler msgHandler = new MessageHandler(handler.getLooper(), callback);
+ callback.setHandler(msgHandler);
+ mCallbacks.add(callback);
+ }
+ }
+
+ public void removeCallback(Callback callback) {
+ mCallbacks.remove(callback);
+ }
+
+ /**
+ * Publish the current playback state to the system and any controllers.
+ * Valid values are defined in {@link RemoteControlClient}. TODO move play
+ * states somewhere else.
+ *
+ * @param state
+ */
+ public void setPlaybackState(int state) {
+ try {
+ mBinder.setPlaybackState(state);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setPlaybackState: ", e);
+ }
+ }
+
+ /**
+ * This must be called when an app has finished performing playback. If
+ * playback is expected to start again shortly the session can be left open,
+ * but it must be released if your activity or service is being destroyed.
+ */
+ public void release() {
+ try {
+ mBinder.destroy();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in onDestroy: ", e);
+ }
+ }
+
+ /**
+ * Retrieve a token object that can be used by apps to create a
+ * {@link MediaController} for interacting with this session. The owner of
+ * the session is responsible for deciding how to distribute these tokens.
+ *
+ * @return A token that can be used to create a MediaController for this
+ * session
+ */
+ public MediaSessionToken getSessionToken() {
+ return mSessionToken;
+ }
+
+ private void postCommand(String command, Bundle extras) {
+ Bundle commandBundle = new Bundle();
+ commandBundle.putString(KEY_COMMAND, command);
+ commandBundle.putBundle(KEY_EXTRAS, extras);
+ synchronized (mLock) {
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ Callback cb = mCallbacks.get(i);
+ Message msg = cb.mHandler.obtainMessage(MESSAGE_COMMAND, commandBundle);
+ cb.mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void postMediaButton(Intent mediaButtonIntent) {
+ synchronized (mLock) {
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ Callback cb = mCallbacks.get(i);
+ Message msg = cb.mHandler.obtainMessage(MESSAGE_MEDIA_BUTTON, mediaButtonIntent);
+ cb.mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ private void postRequestRouteChange(Bundle mediaRouteDescriptor) {
+ synchronized (mLock) {
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ Callback cb = mCallbacks.get(i);
+ Message msg = cb.mHandler.obtainMessage(MESSAGE_ROUTE_CHANGE, mediaRouteDescriptor);
+ cb.mHandler.sendMessage(msg);
+ }
+ }
+ }
+
+ /**
+ * Receives commands or updates from controllers and routes. An app can
+ * specify what commands and buttons it supports by setting them on the
+ * MediaSession (TODO).
+ */
+ public abstract static class Callback {
+ private MessageHandler mHandler;
+
+ public Callback() {
+ }
+
+ /**
+ * Called when a media button is pressed and this session has the
+ * highest priority or a controller sends a media button event to the
+ * session. TODO determine if using Intents identical to the ones
+ * RemoteControlClient receives is useful
+ * <p>
+ * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
+ * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
+ *
+ * @param mediaButtonIntent an intent containing the KeyEvent as an
+ * extra
+ */
+ public void onMediaButton(Intent mediaButtonIntent) {
+ }
+
+ /**
+ * Called when a controller has sent a custom command to this session.
+ * The owner of the session may handle custom commands but is not
+ * required to.
+ *
+ * @param command
+ * @param extras optional
+ */
+ public void onCommand(String command, Bundle extras) {
+ }
+
+ /**
+ * Called when the user has selected a different route to connect to.
+ * The app is responsible for connecting to the new route and migrating
+ * ongoing playback if necessary.
+ *
+ * @param descriptor
+ */
+ public void onRequestRouteChange(Bundle descriptor) {
+ }
+
+ private void setHandler(MessageHandler handler) {
+ mHandler = handler;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static class CallbackStub extends IMediaSessionCallback.Stub {
+ private MediaSession mMediaSession;
+
+ public void setMediaSession(MediaSession session) {
+ mMediaSession = session;
+ }
+
+ @Override
+ public void onCommand(String command, Bundle extras) throws RemoteException {
+ mMediaSession.postCommand(command, extras);
+ }
+
+ @Override
+ public void onMediaButton(Intent mediaButtonIntent) throws RemoteException {
+ mMediaSession.postMediaButton(mediaButtonIntent);
+ }
+
+ @Override
+ public void onRequestRouteChange(Bundle mediaRouteDescriptor) throws RemoteException {
+ mMediaSession.postRequestRouteChange(mediaRouteDescriptor);
+ }
+
+ }
+
+ private class MessageHandler extends Handler {
+ private MediaSession.Callback mCallback;
+
+ public MessageHandler(Looper looper, MediaSession.Callback callback) {
+ super(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ if (mCallback == null) {
+ return;
+ }
+ switch (msg.what) {
+ case MESSAGE_MEDIA_BUTTON:
+ mCallback.onMediaButton((Intent) msg.obj);
+ break;
+ case MESSAGE_COMMAND:
+ Bundle commandBundle = (Bundle) msg.obj;
+ String command = commandBundle.getString(KEY_COMMAND);
+ Bundle extras = commandBundle.getBundle(KEY_EXTRAS);
+ mCallback.onCommand(command, extras);
+ break;
+ case MESSAGE_ROUTE_CHANGE:
+ mCallback.onRequestRouteChange((Bundle) msg.obj);
+ break;
+ }
+ }
+ msg.recycle();
+ }
+ }
+}
diff --git a/media/java/android/media/MediaSessionManager.java b/media/java/android/media/MediaSessionManager.java
new file mode 100644
index 0000000..90f0071
--- /dev/null
+++ b/media/java/android/media/MediaSessionManager.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * MediaSessionManager allows the creation and control of MediaSessions in the
+ * system. A MediaSession enables publishing information about ongoing media and
+ * interacting with MediaControllers and MediaRoutes.
+ * <p>
+ * Use <code>Context.getSystemService(Context.MEDIA_SESSION_SERVICE)</code> to
+ * get an instance of this class.
+ * <p>
+ *
+ * @see MediaSession
+ * @see MediaController
+ */
+public final class MediaSessionManager {
+ private static final String TAG = "MediaSessionManager";
+
+ private final IMediaSessionManager mService;
+
+ private Context mContext;
+
+ /**
+ * @hide
+ */
+ public MediaSessionManager(Context context) {
+ // Consider rewriting like DisplayManagerGlobal
+ // Decide if we need context
+ mContext = context;
+ IBinder b = ServiceManager.getService(Context.MEDIA_SESSION_SERVICE);
+ mService = IMediaSessionManager.Stub.asInterface(b);
+ }
+
+ /**
+ * Creates a new session.
+ *
+ * @param tag A short name for debugging purposes
+ * @return a {@link MediaSession} for the new session
+ */
+ public MediaSession createSession(String tag) {
+ try {
+ MediaSession.CallbackStub cbStub = new MediaSession.CallbackStub();
+ MediaSession session = new MediaSession(mService
+ .createSession(mContext.getPackageName(), cbStub, tag), cbStub);
+ cbStub.setMediaSession(session);
+
+ return session;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create session: ", e);
+ return null;
+ }
+ }
+
+ /**
+ * Get a list of controllers for all ongoing sessions. This requires the
+ * android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by
+ * the calling app.
+ *
+ * @return a list of controllers for ongoing sessions
+ */
+ public List<MediaController> getActiveSessions() {
+ // TODO
+ return new ArrayList<MediaController>();
+ }
+}
diff --git a/media/java/android/media/MediaSessionToken.aidl b/media/java/android/media/MediaSessionToken.aidl
new file mode 100644
index 0000000..e2f1abc
--- /dev/null
+++ b/media/java/android/media/MediaSessionToken.aidl
@@ -0,0 +1,18 @@
+/* Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.media;
+
+parcelable MediaSessionToken;
diff --git a/media/java/android/media/MediaSessionToken.java b/media/java/android/media/MediaSessionToken.java
new file mode 100644
index 0000000..885fda3
--- /dev/null
+++ b/media/java/android/media/MediaSessionToken.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class MediaSessionToken implements Parcelable {
+ private IMediaController mBinder;
+
+ /**
+ * @hide
+ */
+ MediaSessionToken(IMediaController binder) {
+ mBinder = binder;
+ }
+
+ private MediaSessionToken(Parcel in) {
+ mBinder = IMediaController.Stub.asInterface(in.readStrongBinder());
+ }
+
+ /**
+ * @hide
+ */
+ IMediaController getBinder() {
+ return mBinder;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeStrongBinder(mBinder.asBinder());
+ }
+
+ public static final Parcelable.Creator<MediaSessionToken> CREATOR
+ = new Parcelable.Creator<MediaSessionToken>() {
+ @Override
+ public MediaSessionToken createFromParcel(Parcel in) {
+ return new MediaSessionToken(in);
+ }
+
+ @Override
+ public MediaSessionToken[] newArray(int size) {
+ return new MediaSessionToken[size];
+ }
+ };
+}
diff --git a/media/java/android/media/RemoteController.java b/media/java/android/media/RemoteController.java
index cd3ce1f..3711585 100644
--- a/media/java/android/media/RemoteController.java
+++ b/media/java/android/media/RemoteController.java
@@ -264,7 +264,7 @@
* @throws IllegalArgumentException
*/
public boolean sendMediaKeyEvent(KeyEvent keyEvent) throws IllegalArgumentException {
- if (!MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode())) {
+ if (!KeyEvent.isMediaKey(keyEvent.getKeyCode())) {
throw new IllegalArgumentException("not a media key event");
}
final PendingIntent pi;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
index 599522b..d7069cac 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/mediarecorder/MediaRecorderTest.java
@@ -58,6 +58,7 @@
private MediaRecorder mRecorder;
private int MIN_VIDEO_FPS = 5;
+ private int HIGH_SPEED_FPS = 120;
private static final int CAMERA_ID = 0;
@@ -221,10 +222,12 @@
return success;
}
- private boolean recordVideoFromSurface(int frameRate, int width, int height,
+ private boolean recordVideoFromSurface(
+ int frameRate, int captureRate, int width, int height,
int videoFormat, int outFormat, String outFile, boolean videoOnly) {
Log.v(TAG,"recordVideoFromSurface");
MediaRecorder recorder = new MediaRecorder();
+ int sleepTime = 33; // normal capture at 33ms / frame
try {
if (!videoOnly) {
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
@@ -233,6 +236,10 @@
recorder.setOutputFormat(outFormat);
recorder.setOutputFile(outFile);
recorder.setVideoFrameRate(frameRate);
+ if (captureRate > 0) {
+ recorder.setCaptureRate(captureRate);
+ sleepTime = 1000 / captureRate;
+ }
recorder.setVideoSize(width, height);
recorder.setVideoEncoder(videoFormat);
if (!videoOnly) {
@@ -256,7 +263,7 @@
String text = "Frame #" + i;
canvas.drawText(text, 100, 100, paint);
surface.unlockCanvasAndPost(canvas);
- Thread.sleep(33);
+ Thread.sleep(sleepTime);
}
Log.v(TAG, "start");
@@ -270,7 +277,7 @@
String text = "Frame #" + i;
canvas.drawText(text, 100, 100, paint);
surface.unlockCanvasAndPost(canvas);
- Thread.sleep(33);
+ Thread.sleep(sleepTime);
}
Log.v(TAG, "stop");
@@ -517,7 +524,7 @@
String filename = "/sdcard/surface_" +
(k==0?"video_only":"with_audio") + ".3gp";
- success = recordVideoFromSurface(frameRate, 352, 288, codec,
+ success = recordVideoFromSurface(frameRate, 0, 352, 288, codec,
MediaRecorder.OutputFormat.THREE_GPP, filename,
k == 0 ? true : false /* videoOnly */);
if (success) {
@@ -532,4 +539,38 @@
}
assertTrue("testSurfaceRecording", noOfFailure == 0);
}
+
+ // Test recording from surface source with/without audio
+ public void testSurfaceRecordingTimeLapse() {
+ boolean success = false;
+ int noOfFailure = 0;
+ try {
+ int codec = MediaRecorder.VideoEncoder.H264;
+ int frameRate = MediaProfileReader.getMaxFrameRateForCodec(codec);
+ for (int k = 0; k < 2; k++) {
+ // k==0: time lapse test, set capture rate to MIN_VIDEO_FPS
+ // k==1: slow motion test, set capture rate to HIGH_SPEED_FPS
+ String filename = "/sdcard/surface_" +
+ (k==0 ? "time_lapse" : "slow_motion") + ".3gp";
+
+ // always set videoOnly=false, MediaRecorder should disable
+ // audio automatically with time lapse/slow motion
+ success = recordVideoFromSurface(frameRate,
+ k==0 ? MIN_VIDEO_FPS : HIGH_SPEED_FPS,
+ 352, 288, codec,
+ MediaRecorder.OutputFormat.THREE_GPP,
+ filename, false /* videoOnly */);
+ if (success) {
+ success = validateVideo(filename, 352, 288);
+ }
+ if (!success) {
+ noOfFailure++;
+ }
+ }
+ } catch (Exception e) {
+ Log.v(TAG, e.toString());
+ }
+ assertTrue("testSurfaceRecordingTimeLapse", noOfFailure == 0);
+ }
+
}
diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java
index b93557d..b6dd9c2 100644
--- a/opengl/java/android/opengl/EGL14.java
+++ b/opengl/java/android/opengl/EGL14.java
@@ -155,10 +155,18 @@
);
// C function EGLDisplay eglGetDisplay ( EGLNativeDisplayType display_id )
+ // TODO Deprecate the eglGetDisplay(int) API method
public static native EGLDisplay eglGetDisplay(
int display_id
);
+ // TODO Unhide the eglGetDisplay(long) API method
+ /**
+ * {@hide}
+ */
+ public static native EGLDisplay eglGetDisplay(
+ long display_id
+ );
// C function EGLBoolean eglInitialize ( EGLDisplay dpy, EGLint *major, EGLint *minor )
@@ -324,7 +332,7 @@
);
// C function EGLSurface eglCreatePbufferFromClientBuffer ( EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list )
-
+ // TODO Deprecate the below method
public static native EGLSurface eglCreatePbufferFromClientBuffer(
EGLDisplay dpy,
int buftype,
@@ -333,6 +341,18 @@
int[] attrib_list,
int offset
);
+ // TODO Unhide the below method
+ /**
+ * {@hide}
+ */
+ public static native EGLSurface eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy,
+ int buftype,
+ long buffer,
+ EGLConfig config,
+ int[] attrib_list,
+ int offset
+ );
// C function EGLBoolean eglSurfaceAttrib ( EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value )
diff --git a/opengl/java/android/opengl/EGLConfig.java b/opengl/java/android/opengl/EGLConfig.java
index a7a6bbb..9881070 100644
--- a/opengl/java/android/opengl/EGLConfig.java
+++ b/opengl/java/android/opengl/EGLConfig.java
@@ -22,7 +22,7 @@
*
*/
public class EGLConfig extends EGLObjectHandle {
- private EGLConfig(int handle) {
+ private EGLConfig(long handle) {
super(handle);
}
@@ -32,6 +32,6 @@
if (!(o instanceof EGLConfig)) return false;
EGLConfig that = (EGLConfig) o;
- return getHandle() == that.getHandle();
+ return getNativeHandle() == that.getNativeHandle();
}
}
diff --git a/opengl/java/android/opengl/EGLContext.java b/opengl/java/android/opengl/EGLContext.java
index c93bd6e..f791e7e 100644
--- a/opengl/java/android/opengl/EGLContext.java
+++ b/opengl/java/android/opengl/EGLContext.java
@@ -22,7 +22,7 @@
*
*/
public class EGLContext extends EGLObjectHandle {
- private EGLContext(int handle) {
+ private EGLContext(long handle) {
super(handle);
}
@@ -32,6 +32,6 @@
if (!(o instanceof EGLContext)) return false;
EGLContext that = (EGLContext) o;
- return getHandle() == that.getHandle();
+ return getNativeHandle() == that.getNativeHandle();
}
}
diff --git a/opengl/java/android/opengl/EGLDisplay.java b/opengl/java/android/opengl/EGLDisplay.java
index 5b8043a..e872761 100644
--- a/opengl/java/android/opengl/EGLDisplay.java
+++ b/opengl/java/android/opengl/EGLDisplay.java
@@ -22,7 +22,7 @@
*
*/
public class EGLDisplay extends EGLObjectHandle {
- private EGLDisplay(int handle) {
+ private EGLDisplay(long handle) {
super(handle);
}
@@ -32,6 +32,6 @@
if (!(o instanceof EGLDisplay)) return false;
EGLDisplay that = (EGLDisplay) o;
- return getHandle() == that.getHandle();
+ return getNativeHandle() == that.getNativeHandle();
}
}
diff --git a/opengl/java/android/opengl/EGLObjectHandle.java b/opengl/java/android/opengl/EGLObjectHandle.java
index d2710de..e6e3976 100644
--- a/opengl/java/android/opengl/EGLObjectHandle.java
+++ b/opengl/java/android/opengl/EGLObjectHandle.java
@@ -22,12 +22,20 @@
*
*/
public abstract class EGLObjectHandle {
- private final int mHandle;
+ private final long mHandle;
+ // TODO Deprecate EGLObjectHandle(int) method
protected EGLObjectHandle(int handle) {
mHandle = handle;
}
-
+ // TODO Unhide the EGLObjectHandle(long) method
+ /**
+ * {@hide}
+ */
+ protected EGLObjectHandle(long handle) {
+ mHandle = handle;
+ }
+ // TODO Deprecate getHandle() method in favor of getNativeHandle()
/**
* Returns the native handle of the wrapped EGL object. This handle can be
* cast to the corresponding native type on the native side.
@@ -37,11 +45,27 @@
* @return the native handle of the wrapped EGL object.
*/
public int getHandle() {
- return mHandle;
+ if ((mHandle & 0xffffffffL) != mHandle) {
+ throw new UnsupportedOperationException();
+ }
+ return (int)mHandle;
}
+ // TODO Unhide getNativeHandle() method
+ /**
+ * {@hide}
+ */
+ public long getNativeHandle() {
+ return mHandle;
+ }
@Override
public int hashCode() {
- return getHandle();
+ /*
+ * Based on the algorithm suggested in
+ * http://developer.android.com/reference/java/lang/Object.html
+ */
+ int result = 17;
+ result = 31 * result + (int) (mHandle ^ (mHandle >>> 32));
+ return result;
}
}
diff --git a/opengl/java/android/opengl/EGLSurface.java b/opengl/java/android/opengl/EGLSurface.java
index c379dc9..c200f72 100644
--- a/opengl/java/android/opengl/EGLSurface.java
+++ b/opengl/java/android/opengl/EGLSurface.java
@@ -22,7 +22,7 @@
*
*/
public class EGLSurface extends EGLObjectHandle {
- private EGLSurface(int handle) {
+ private EGLSurface(long handle) {
super(handle);
}
@@ -32,6 +32,6 @@
if (!(o instanceof EGLSurface)) return false;
EGLSurface that = (EGLSurface) o;
- return getHandle() == that.getHandle();
+ return getNativeHandle() == that.getNativeHandle();
}
}
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index 8261474..137f2f5 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -823,6 +823,7 @@
// C function void glGetActiveAttrib ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
+ /** @hide Method is broken, but used to be public (b/6006380) */
public static native void glGetActiveAttrib(
int program,
int index,
@@ -870,6 +871,7 @@
// C function void glGetActiveUniform ( GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name )
+ /** @hide Method is broken, but used to be public (b/6006380) */
public static native void glGetActiveUniform(
int program,
int index,
@@ -1107,6 +1109,7 @@
// C function void glGetShaderSource ( GLuint shader, GLsizei bufsize, GLsizei *length, char *source )
+ /** @hide Method is broken, but used to be public (b/6006380) */
public static native void glGetShaderSource(
int shader,
int bufsize,
diff --git a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
index 619a6db..4e35b91 100644
--- a/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-sw/strings.xml
@@ -18,17 +18,17 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="backup_confirm_title" msgid="827563724209303345">"Kuhifadhi kikamilifu"</string>
<string name="restore_confirm_title" msgid="5469365809567486602">"Kurejesha kila kitu"</string>
- <string name="backup_confirm_text" msgid="1878021282758896593">"Chelezo kamili la data iliyounganishwa kwenye eneo kazi la kompyuta limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuomba chelezo mwenyewe, usikubali uendeshaji kuendelea."</string>
+ <string name="backup_confirm_text" msgid="1878021282758896593">"Ombi la kuhifadhi nakala rudufu kamili za data kwenye eneo kazi la kompyuta iliyounganishwa limewasilishwa. Ungependa shughuli hii ufanyike?\n\n Ikiwa sio wewe uliyewasilisha ombi hili, usikubali shughuli hii iendelee."</string>
<string name="allow_backup_button_label" msgid="4217228747769644068">"Hifadhi nakala ya data yangu"</string>
<string name="deny_backup_button_label" msgid="6009119115581097708">"Usicheleze"</string>
<string name="restore_confirm_text" msgid="7499866728030461776">"Kurejesha kamili kwa data nzima kutoka kwa eneo kazi la kompyuta lililounganishwa limeombwa. Unataka kuruhusu hii kutendeka?\n\n Ikiwa hukuweza kurejesha upya mwenyewe, usiruhusu uendeshaji huu kuendelea. Hii itaweka upya data yoyote iliyo kwenye kifaa hiki sasa!"</string>
<string name="allow_restore_button_label" msgid="3081286752277127827">"Rejesha upya data yangu"</string>
<string name="deny_restore_button_label" msgid="1724367334453104378">"Usirejeshe upya"</string>
- <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri lako la chelezo hapo chini:"</string>
+ <string name="current_password_text" msgid="8268189555578298067">"Tafadhali ingiza nenosiri unalotumia kuhifadhi nakala rudufu hapo chini:"</string>
<string name="device_encryption_restore_text" msgid="1570864916855208992">"Tafadhali ingiza nenosiri la usimbaji fiche wa kifaa chako hapo chini."</string>
<string name="device_encryption_backup_text" msgid="5866590762672844664">"Tafadhali ingiza nenosiri lako la msimbo fiche hapo chini. Pia litatumika kusimba fiche jalidi ya hifadhi."</string>
- <string name="backup_enc_password_text" msgid="4981585714795233099">"Tafadhali ingiza nenosiri la kutumia kwa usimbaji fiche wa chelezo ya data kamili. Ikiwa hii itawachwa wazi, nenosiri lako la sasa litatumika:"</string>
- <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ikiwa unataka kusimba fiche data nzima ya kucheleza, ingiza nenosiri la hapo chini:"</string>
+ <string name="backup_enc_password_text" msgid="4981585714795233099">"Tafadhali ingiza nenosiri la kutumia katika kusimba nakala rudufu kamili za data kwa njia fiche. Ikiwa hii itawachwa wazi, nenosiri lako la sasa litatumika:"</string>
+ <string name="backup_enc_password_optional" msgid="1350137345907579306">"Ikiwa unataka kusimba kwa njia fiche nakala rudufu za data, ingiza nenosiri lililo hapo chini:"</string>
<string name="restore_enc_password_text" msgid="6140898525580710823">"Ikiwa data iliyorejeshwa upya, tafadhali ingiza nenosiri lililo hapo chini:"</string>
<string name="toast_backup_started" msgid="550354281452756121">"Inaanza kuhifadhi..."</string>
<string name="toast_backup_ended" msgid="3818080769548726424">"Imemaliza kuhifadhi"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
index 7ac94bd..1e79ee4 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java
@@ -1051,9 +1051,6 @@
}
private void enableUserSelectorIfNecessary() {
- if (!UserManager.supportsMultipleUsers()) {
- return; // device doesn't support multi-user mode
- }
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
if (um == null) {
Throwable t = new Throwable();
@@ -1063,61 +1060,53 @@
}
// if there are multiple users, we need to enable to multi-user switcher
- final List<UserInfo> users = um.getUsers(true);
- if (users == null) {
- Throwable t = new Throwable();
- t.fillInStackTrace();
- Log.e(TAG, "list of users is null.", t);
+ if (!um.isUserSwitcherEnabled()) {
return;
}
final View multiUserView = findViewById(R.id.keyguard_user_selector);
if (multiUserView == null) {
- Throwable t = new Throwable();
- t.fillInStackTrace();
- Log.e(TAG, "can't find user_selector in layout.", t);
+ if (DEBUG) Log.d(TAG, "can't find user_selector in layout.");
return;
}
- if (users.size() > 1) {
- if (multiUserView instanceof KeyguardMultiUserSelectorView) {
- mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
- mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
- mKeyguardMultiUserSelectorView.addUsers(users);
- UserSwitcherCallback callback = new UserSwitcherCallback() {
- @Override
- public void hideSecurityView(int duration) {
- getSecurityContainer().animate().alpha(0).setDuration(duration);
- }
-
- @Override
- public void showSecurityView() {
- getSecurityContainer().setAlpha(1.0f);
- }
-
- @Override
- public void showUnlockHint() {
- if (getSecurityContainer() != null) {
- getSecurityContainer().showUsabilityHint();
- }
- }
-
- @Override
- public void userActivity() {
- if (mViewMediatorCallback != null) {
- mViewMediatorCallback.userActivity();
- }
- }
- };
- mKeyguardMultiUserSelectorView.setCallback(callback);
- } else {
- Throwable t = new Throwable();
- t.fillInStackTrace();
- if (multiUserView == null) {
- Log.e(TAG, "could not find the user_selector.", t);
- } else {
- Log.e(TAG, "user_selector is the wrong type.", t);
+ if (multiUserView instanceof KeyguardMultiUserSelectorView) {
+ mKeyguardMultiUserSelectorView = (KeyguardMultiUserSelectorView) multiUserView;
+ mKeyguardMultiUserSelectorView.setVisibility(View.VISIBLE);
+ mKeyguardMultiUserSelectorView.addUsers(um.getUsers(true));
+ UserSwitcherCallback callback = new UserSwitcherCallback() {
+ @Override
+ public void hideSecurityView(int duration) {
+ getSecurityContainer().animate().alpha(0).setDuration(duration);
}
+
+ @Override
+ public void showSecurityView() {
+ getSecurityContainer().setAlpha(1.0f);
+ }
+
+ @Override
+ public void showUnlockHint() {
+ if (getSecurityContainer() != null) {
+ getSecurityContainer().showUsabilityHint();
+ }
+ }
+
+ @Override
+ public void userActivity() {
+ if (mViewMediatorCallback != null) {
+ mViewMediatorCallback.userActivity();
+ }
+ }
+ };
+ mKeyguardMultiUserSelectorView.setCallback(callback);
+ } else {
+ Throwable t = new Throwable();
+ t.fillInStackTrace();
+ if (multiUserView == null) {
+ Log.e(TAG, "could not find the user_selector.", t);
+ } else {
+ Log.e(TAG, "user_selector is the wrong type.", t);
}
}
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
index 7975d8e..06815e1 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardMultiUserSelectorView.java
@@ -76,11 +76,13 @@
Collections.sort(users, mOrderAddedComparator);
for (UserInfo user: users) {
- KeyguardMultiUserAvatar uv = createAndAddUser(user);
- if (user.id == activeUser.id) {
- mActiveUserAvatar = uv;
+ if (user.supportsSwitchTo()) {
+ KeyguardMultiUserAvatar uv = createAndAddUser(user);
+ if (user.id == activeUser.id) {
+ mActiveUserAvatar = uv;
+ }
+ uv.setActive(false, false, null);
}
- uv.setActive(false, false, null);
}
mActiveUserAvatar.lockPressed(true);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
index baf520e..43165eb 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewManager.java
@@ -330,7 +330,7 @@
private boolean allowNotificationsOnSecureKeyguard() {
ContentResolver cr = mContext.getContentResolver();
- return Settings.Secure.getInt(cr, Settings.Secure.LOCK_SCREEN_ALLOW_NOTIFICATIONS, 0) == 1;
+ return Settings.Global.getInt(cr, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) == 1;
}
private KeyguardViewBase inflateKeyguardView(Bundle options, int layoutId) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
index 914fdc4..151177e 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardViewMediator.java
@@ -151,13 +151,13 @@
/**
* Allow the user to expand the status bar when a SECURE keyguard is engaged
- * and {@link Settings.Secure#LOCK_SCREEN_ALLOW_NOTIFICATIONS} is set
+ * and {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS} is set
* (private notifications will be masked).
*/
private static final boolean ENABLE_SECURE_STATUS_BAR_EXPAND = true;
/**
- * Default value of {@link Settings.Secure#LOCK_SCREEN_ALLOW_NOTIFICATIONS}.
+ * Default value of {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
*/
private static final boolean ALLOW_NOTIFICATIONS_DEFAULT = false;
@@ -258,7 +258,7 @@
private int mLockSoundStreamId;
/**
- * Tracks value of {@link Settings.Secure#LOCK_SCREEN_ALLOW_NOTIFICATIONS}.
+ * Tracks value of {@link Settings.Global#LOCK_SCREEN_SHOW_NOTIFICATIONS}.
*/
private boolean mAllowNotificationsWhenSecure;
@@ -704,7 +704,7 @@
private void maybeSendUserPresentBroadcast() {
if (mSystemReady && mLockPatternUtils.isLockScreenDisabled()
- && mUserManager.getUsers(true).size() == 1) {
+ && !mUserManager.isUserSwitcherEnabled()) {
// Lock screen is disabled because the user has set the preference to "None".
// In this case, send out ACTION_USER_PRESENT here instead of in
// handleKeyguardDone()
@@ -913,9 +913,9 @@
// note whether notification access should be allowed
mAllowNotificationsWhenSecure = ENABLE_SECURE_STATUS_BAR_EXPAND
- && 0 != Settings.Secure.getInt(
+ && 0 != Settings.Global.getInt(
mContext.getContentResolver(),
- Settings.Secure.LOCK_SCREEN_ALLOW_NOTIFICATIONS,
+ Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
ALLOW_NOTIFICATIONS_DEFAULT ? 1 : 0);
// if the keyguard is already showing, don't bother
@@ -940,7 +940,7 @@
return;
}
- if (mUserManager.getUsers(true).size() < 2
+ if (!mUserManager.isUserSwitcherEnabled()
&& mLockPatternUtils.isLockScreenDisabled() && !lockedOrMissing) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
return;
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 69f7152..7410b9d 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -183,4 +183,7 @@
<!-- Default for Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE -->
<integer name="def_wifi_scan_always_available">0</integer>
+ <!-- Default for Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
+ <integer name="def_lock_screen_show_notifications">1</integer>
+
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f316d88..b546689 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -69,7 +69,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 98;
+ private static final int DATABASE_VERSION = 99;
private Context mContext;
private int mUserHandle;
@@ -1556,6 +1556,24 @@
upgradeVersion = 98;
}
+ if (upgradeVersion == 98) {
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
+ + " VALUES(?,?);");
+ loadIntegerSetting(stmt, Settings.Global.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ R.integer.def_lock_screen_show_notifications);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ }
+ upgradeVersion = 99;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/res/anim/hydraulic_brake_interpolator.xml b/packages/SystemUI/res/anim/hydraulic_brake_interpolator.xml
deleted file mode 100644
index 5b6778e..0000000
--- a/packages/SystemUI/res/anim/hydraulic_brake_interpolator.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/anim/ease_out_interpolator.xml
-**
-** Copyright 2007, 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.
-*/
--->
-
-<decelerateInterpolator
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:factor="10.0" />
diff --git a/packages/SystemUI/res/anim/lights_out_out.xml b/packages/SystemUI/res/anim/lights_out_out.xml
deleted file mode 100644
index 610ac7a..0000000
--- a/packages/SystemUI/res/anim/lights_out_out.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:toYDelta="-100%p" android:fromYDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
- <alpha android:toAlpha="0.5" android:fromAlpha="1.0"
- android:duration="@android:integer/config_longAnimTime"
- />
-</set>
diff --git a/packages/SystemUI/res/anim/notification_dnd_on.xml b/packages/SystemUI/res/anim/notification_dnd_on.xml
deleted file mode 100644
index 309943b..0000000
--- a/packages/SystemUI/res/anim/notification_dnd_on.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- >
- <translate android:toXDelta="100%p" android:fromXDelta="0"
- android:duration="@android:integer/config_longAnimTime"
- android:interpolator="@anim/hydraulic_brake_interpolator"
- />
-</set>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 9ed493c..9336ade 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -125,7 +125,7 @@
<string name="accessibility_data_connection_4g" msgid="7741000750630089612">"4G"</string>
<string name="accessibility_data_connection_lte" msgid="5413468808637540658">"LTE"</string>
<string name="accessibility_data_connection_cdma" msgid="6132648193978823023">"CDMA"</string>
- <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Inatumia data nje mtandao wako"</string>
+ <string name="accessibility_data_connection_roaming" msgid="5977362333466556094">"Inatumia data nje mtandao wako wa kawaida"</string>
<string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Ukingo"</string>
<string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
<string name="accessibility_no_sim" msgid="8274017118472455155">"Hakuna SIM."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index b5c24d7..033e56d 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -72,7 +72,7 @@
<string name="use_mtp_button_title" msgid="4333504413563023626">"ต่อเชื่อมเป็นโปรแกรมเล่นสื่อ (MTP)"</string>
<string name="use_ptp_button_title" msgid="7517127540301625751">"ต่อเชื่อมเป็นกล้องถ่ายรูป (PTP)"</string>
<string name="installer_cd_button_title" msgid="2312667578562201583">"ติดตั้งแอปพลิเคชัน Android File Transfer ของ Mac"</string>
- <string name="accessibility_back" msgid="567011538994429120">"ย้อนกลับ"</string>
+ <string name="accessibility_back" msgid="567011538994429120">"กลับ"</string>
<string name="accessibility_home" msgid="8217216074895377641">"หน้าแรก"</string>
<string name="accessibility_menu" msgid="316839303324695949">"เมนู"</string>
<string name="accessibility_recent" msgid="8571350598987952883">"แอปพลิเคชันล่าสุด"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 91ae973..7ff52de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -46,6 +46,7 @@
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.IWindowManager;
import android.view.LayoutInflater;
@@ -131,7 +132,10 @@
protected IDreamManager mDreamManager;
PowerManager mPowerManager;
protected int mRowHeight;
- private boolean mPublicMode = false;
+
+ // public mode, private notifications, etc
+ private boolean mLockscreenPublicMode = false;
+ private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
// UI-specific methods
@@ -159,7 +163,7 @@
return mDeviceProvisioned;
}
- private ContentObserver mProvisioningObserver = new ContentObserver(new Handler()) {
+ private final ContentObserver mProvisioningObserver = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
final boolean provisioned = 0 != Settings.Global.getInt(
@@ -171,6 +175,17 @@
}
};
+ private final ContentObserver mLockscreenSettingsObserver = new ContentObserver(mHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ // We don't know which user changed LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS,
+ // so we just dump our cache ...
+ mUsersAllowingPrivateNotifications.clear();
+ // ... and refresh all the notifications
+ updateNotificationIcons();
+ }
+ };
+
private RemoteViews.OnClickHandler mOnClickHandler = new RemoteViews.OnClickHandler() {
@Override
public boolean onClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) {
@@ -229,6 +244,12 @@
Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
mProvisioningObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ mLockscreenSettingsObserver,
+ UserHandle.USER_ALL);
+
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
@@ -550,12 +571,35 @@
public abstract void resetHeadsUpDecayTimer();
- public void setPublicMode(boolean publicMode) {
- mPublicMode = publicMode;
+ /**
+ * Save the current "public" (locked and secure) state of the lockscreen.
+ */
+ public void setLockscreenPublicMode(boolean publicMode) {
+ mLockscreenPublicMode = publicMode;
}
- public boolean isPublicMode() {
- return mPublicMode;
+ public boolean isLockscreenPublicMode() {
+ return mLockscreenPublicMode;
+ }
+
+ /**
+ * Has the given user chosen to allow their private (full) notifications to be shown even
+ * when the lockscreen is in "public" (secure & locked) mode?
+ */
+ public boolean userAllowsPrivateNotificationsInPublic(int userHandle) {
+ if (userHandle == UserHandle.USER_ALL) {
+ return true;
+ }
+
+ if (mUsersAllowingPrivateNotifications.indexOfKey(userHandle) < 0) {
+ final boolean allowed = 0 != Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0, userHandle);
+ mUsersAllowingPrivateNotifications.append(userHandle, allowed);
+ return allowed;
+ }
+
+ return mUsersAllowingPrivateNotifications.get(userHandle);
}
protected class H extends Handler {
@@ -1136,8 +1180,9 @@
StatusBarNotification notification, boolean isHeadsUp) {
final RemoteViews contentView = notification.getNotification().contentView;
final RemoteViews bigContentView = notification.getNotification().bigContentView;
- final RemoteViews publicContentView
- = notification.getNotification().publicVersion.contentView;
+ final Notification publicVersion = notification.getNotification().publicVersion;
+ final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
+ : null;
// Reapply the RemoteViews
contentView.reapply(mContext, entry.expanded, mOnClickHandler);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 4427466..b9a59dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -71,9 +71,9 @@
final StatusBarNotification na = a.notification;
final StatusBarNotification nb = b.notification;
int d = na.getScore() - nb.getScore();
- if (a.interruption != b.interruption) {
- return a.interruption ? 1 : -1;
- } else if (d != 0) {
+ if (a.interruption != b.interruption) {
+ return a.interruption ? 1 : -1;
+ } else if (d != 0) {
return d;
} else {
return (int) (na.getNotification().when - nb.getNotification().when);
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 e5bdd59..2114991 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1033,8 +1033,10 @@
if (!notificationIsForCurrentUser(ent.notification)) continue;
final int vis = ent.notification.getNotification().visibility;
if (vis != Notification.VISIBILITY_SECRET) {
- // when isPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
- ent.row.setShowingPublic(isPublicMode() && vis == Notification.VISIBILITY_PRIVATE);
+ // when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications
+ ent.row.setShowingPublic(isLockscreenPublicMode()
+ && vis == Notification.VISIBILITY_PRIVATE
+ && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId()));
toShow.add(ent.row);
}
}
@@ -1087,9 +1089,10 @@
if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE)
|| showNotificationEvenIfUnprovisioned(ent.notification))) continue;
if (!notificationIsForCurrentUser(ent.notification)) continue;
- if (isPublicMode()
+ if (isLockscreenPublicMode()
&& ent.notification.getNotification().visibility
- == Notification.VISIBILITY_SECRET) {
+ == Notification.VISIBILITY_SECRET
+ && !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId())) {
// in "public" mode (atop a secure keyguard), secret notifs are totally hidden
continue;
}
@@ -1343,10 +1346,10 @@
} else if ((diff & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) {
if ((state & StatusBarManager.DISABLE_PRIVATE_NOTIFICATIONS) != 0) {
// we are outside a secure keyguard, so we need to switch to "public" mode
- setPublicMode(true);
+ setLockscreenPublicMode(true);
} else {
// user has authenticated the device; full notifications may be shown
- setPublicMode(false);
+ setLockscreenPublicMode(false);
}
updateNotificationIcons();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 4d7ff5e..bcb818a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -312,7 +312,7 @@
public void onClick(View v) {
collapsePanels();
final UserManager um = UserManager.get(mContext);
- if (um.getUsers(true).size() > 1) {
+ if (um.isUserSwitcherEnabled()) {
// Since keyguard and systemui were merged into the same process to save
// memory, they share the same Looper and graphics context. As a result,
// there's no way to allow concurrent animation while keyguard inflates.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 11cba7b..48ee1ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -782,7 +782,6 @@
void addRemoteDisplayTile(QuickSettingsTileView view, RefreshCallback cb) {
mRemoteDisplayTile = view;
mRemoteDisplayCallback = cb;
- final int[] count = new int[1];
mRemoteDisplayTile.setOnPrepareListener(new QuickSettingsTileView.OnPrepareListener() {
@Override
public void onPrepare() {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 2c36ab7..0adb32f 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -311,6 +311,8 @@
}
mUsbStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+ mUsbStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
+
final boolean adbOn = 1 == Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.ADB_ENABLED,
@@ -401,6 +403,7 @@
mMediaStorageNotification.icon = icon;
mMediaStorageNotification.setLatestEventInfo(mContext, title, message, pi);
+ mMediaStorageNotification.visibility = Notification.VISIBILITY_PUBLIC;
}
final int notificationId = mMediaStorageNotification.icon;
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index f82ca22..0120a03 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -363,36 +363,38 @@
}
private void addUsersToMenu(ArrayList<Action> items) {
- List<UserInfo> users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE))
- .getUsers();
- if (users.size() > 1) {
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (um.isUserSwitcherEnabled()) {
+ List<UserInfo> users = um.getUsers();
UserInfo currentUser = getCurrentUser();
for (final UserInfo user : users) {
- boolean isCurrentUser = currentUser == null
- ? user.id == 0 : (currentUser.id == user.id);
- Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
- : null;
- SinglePressAction switchToUser = new SinglePressAction(
- com.android.internal.R.drawable.ic_menu_cc, icon,
- (user.name != null ? user.name : "Primary")
- + (isCurrentUser ? " \u2714" : "")) {
- public void onPress() {
- try {
- ActivityManagerNative.getDefault().switchUser(user.id);
- } catch (RemoteException re) {
- Log.e(TAG, "Couldn't switch user " + re);
+ if (user.supportsSwitchTo()) {
+ boolean isCurrentUser = currentUser == null
+ ? user.id == 0 : (currentUser.id == user.id);
+ Drawable icon = user.iconPath != null ? Drawable.createFromPath(user.iconPath)
+ : null;
+ SinglePressAction switchToUser = new SinglePressAction(
+ com.android.internal.R.drawable.ic_menu_cc, icon,
+ (user.name != null ? user.name : "Primary")
+ + (isCurrentUser ? " \u2714" : "")) {
+ public void onPress() {
+ try {
+ ActivityManagerNative.getDefault().switchUser(user.id);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Couldn't switch user " + re);
+ }
}
- }
- public boolean showDuringKeyguard() {
- return true;
- }
+ public boolean showDuringKeyguard() {
+ return true;
+ }
- public boolean showBeforeProvisioning() {
- return false;
- }
- };
- items.add(switchToUser);
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+ };
+ items.add(switchToUser);
+ }
}
}
}
diff --git a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
index 3cc74fc..5602206 100644
--- a/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
+++ b/policy/src/com/android/internal/policy/impl/ImmersiveModeConfirmation.java
@@ -84,9 +84,9 @@
return exit != null ? exit.getDuration() : 0;
}
- public void loadSetting() {
+ public void loadSetting(int currentUserId) {
mConfirmed = false;
- mCurrentUserId = getCurrentUser();
+ mCurrentUserId = currentUserId;
if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d resetForPanic=%s",
mCurrentUserId, mUserPanicResets.get(mCurrentUserId, false)));
String value = null;
@@ -159,14 +159,6 @@
saveSetting();
}
- private int getCurrentUser() {
- try {
- return ActivityManagerNative.getDefault().getCurrentUser().id;
- } catch (RemoteException e) {
- throw new IllegalStateException(e); // local call
- }
- }
-
private void handleHide() {
if (mClingWindow != null) {
if (DEBUG) Slog.d(TAG, "Hiding immersive mode confirmation");
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index ece4fe7..abc3fb1 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1168,7 +1168,7 @@
updateRotation = true;
}
if (mImmersiveModeConfirmation != null) {
- mImmersiveModeConfirmation.loadSetting();
+ mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
}
PolicyControl.reloadFromSetting(mContext);
}
@@ -1661,7 +1661,8 @@
return view.getParent() != null ? view : null;
} catch (WindowManager.BadTokenException e) {
// ignore
- Log.w(TAG, appToken + " already running, starting window not displayed");
+ Log.w(TAG, appToken + " already running, starting window not displayed. " +
+ e.getMessage());
} catch (RuntimeException e) {
// don't crash if something else bad happens, for example a
// failure loading resources because we are loading from an app
@@ -2569,7 +2570,8 @@
@Override
public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) {
final int fl = PolicyControl.getWindowFlags(null, attrs);
- final int systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
+ final int sysuiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int systemUiVisibility = (sysuiVis | attrs.subtreeSystemUiVisibility);
if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR))
== (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
@@ -2953,7 +2955,7 @@
final int fl = PolicyControl.getWindowFlags(win, attrs);
final int sim = attrs.softInputMode;
- final int sysUiFl = PolicyControl.getSystemUiVisibility(win);
+ final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null);
final Rect pf = mTmpParentFrame;
final Rect df = mTmpDisplayFrame;
@@ -3798,14 +3800,11 @@
if (keyCode == KeyEvent.KEYCODE_POWER) {
policyFlags |= WindowManagerPolicy.FLAG_WAKE;
}
- final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
- | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTq keycode=" + keyCode
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive
- + " policyFlags=" + Integer.toHexString(policyFlags)
- + " isWakeKey=" + isWakeKey);
+ + " policyFlags=" + Integer.toHexString(policyFlags));
}
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
@@ -3822,6 +3821,8 @@
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
+ boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE
+ | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isScreenOn || (isInjected && !isWakeKey)) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
@@ -3829,8 +3830,8 @@
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
- if (down && isWakeKey && isWakeKeyWhenScreenOff(keyCode)) {
- result |= ACTION_WAKE_UP;
+ if (isWakeKey && (!down || !isWakeKeyWhenScreenOff(keyCode))) {
+ isWakeKey = false;
}
}
@@ -3940,7 +3941,8 @@
}
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime());
+ isWakeKey = false;
}
}
}
@@ -3987,7 +3989,8 @@
mPowerKeyTriggered = false;
cancelPendingScreenshotChordAction();
if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
- result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
+ mPowerManager.goToSleep(event.getEventTime());
+ isWakeKey = false;
}
mPendingPowerKeyUpCanceled = false;
}
@@ -4057,6 +4060,10 @@
break;
}
}
+
+ if (isWakeKey) {
+ mPowerManager.wakeUp(event.getEventTime());
+ }
return result;
}
@@ -4097,13 +4104,13 @@
/** {@inheritDoc} */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
int result = 0;
final boolean isWakeMotion = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
if (isWakeMotion) {
- result |= ACTION_WAKE_UP;
+ mPowerManager.wakeUp(whenNanos / 1000000);
}
return result;
}
@@ -5078,7 +5085,7 @@
return 0;
}
- int tmpVisibility = PolicyControl.getSystemUiVisibility(win)
+ int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
& ~mResettingSystemUiFlags
& ~mForceClearedSystemUiFlags;
if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
diff --git a/policy/src/com/android/internal/policy/impl/PolicyControl.java b/policy/src/com/android/internal/policy/impl/PolicyControl.java
index 4f355dd..ffdb520 100644
--- a/policy/src/com/android/internal/policy/impl/PolicyControl.java
+++ b/policy/src/com/android/internal/policy/impl/PolicyControl.java
@@ -61,16 +61,17 @@
private static Filter sImmersiveStatusFilter;
private static Filter sImmersiveNavigationFilter;
- public static int getSystemUiVisibility(WindowState win) {
- int vis = win.getSystemUiVisibility();
- if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+ public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int vis = win != null ? win.getSystemUiVisibility() : attrs.systemUiVisibility;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
vis &= ~(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.STATUS_BAR_TRANSLUCENT);
}
- if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
vis |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -81,20 +82,22 @@
}
public static int getWindowFlags(WindowState win, LayoutParams attrs) {
- int flags = (attrs != null ? attrs : win.getAttrs()).flags;
- if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+ attrs = attrs != null ? attrs : win.getAttrs();
+ int flags = attrs.flags;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
flags &= ~(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
- if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(win)) {
+ if (sImmersiveNavigationFilter != null && sImmersiveNavigationFilter.matches(attrs)) {
flags &= ~WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
}
return flags;
}
public static int adjustClearableFlags(WindowState win, int clearableFlags) {
- if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(win)) {
+ final LayoutParams attrs = win != null ? win.getAttrs() : null;
+ if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
}
return clearableFlags;
@@ -187,9 +190,7 @@
mBlacklist = blacklist;
}
- boolean matches(WindowState win) {
- if (win == null) return false;
- LayoutParams attrs = win.getAttrs();
+ boolean matches(LayoutParams attrs) {
if (attrs == null) return false;
boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
diff --git a/rs/java/android/renderscript/AllocationAdapter.java b/rs/java/android/renderscript/AllocationAdapter.java
index 6c1b1ed..3522a52 100644
--- a/rs/java/android/renderscript/AllocationAdapter.java
+++ b/rs/java/android/renderscript/AllocationAdapter.java
@@ -219,7 +219,6 @@
}
static public AllocationAdapter create2D(RenderScript rs, Allocation a) {
- android.util.Log.e("rs", "create2d " + a);
rs.validate();
AllocationAdapter aa = new AllocationAdapter(0, rs, a);
aa.mConstrainedLOD = true;
diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java
index 842aa23..b386dd7 100644
--- a/rs/java/android/renderscript/BaseObj.java
+++ b/rs/java/android/renderscript/BaseObj.java
@@ -122,7 +122,8 @@
// must include nObjDestroy in the critical section
ReentrantReadWriteLock.ReadLock rlock = mRS.mRWLock.readLock();
rlock.lock();
- if(mRS.isAlive()) {
+ // AllocationAdapters are BaseObjs with an ID of 0 but should not be passed to nObjDestroy
+ if(mRS.isAlive() && mID != 0) {
mRS.nObjDestroy(mID);
}
rlock.unlock();
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index a4a9070..89dba9f 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -99,6 +99,20 @@
static File mCacheDir;
+ // this should be a monotonically increasing ID
+ // used in conjunction with the API version of a device
+ static final long sMinorID = 1;
+
+ /**
+ * Returns an identifier that can be used to identify a particular
+ * minor version of RS.
+ *
+ * @hide
+ */
+ public static long getMinorID() {
+ return sMinorID;
+ }
+
/**
* Sets the directory to use as a persistent storage for the
* renderscript object file cache.
diff --git a/services/Android.mk b/services/Android.mk
index a8881b6..5260540 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -8,13 +8,23 @@
LOCAL_SRC_FILES := $(call all-java-files-under,java)
-LOCAL_STATIC_JAVA_LIBRARIES := \
- services.core \
- services.accessibility \
- services.appwidget \
- services.backup \
- services.devicepolicy \
- services.print
+# Uncomment to enable output of certain warnings (deprecated, unchecked)
+# LOCAL_JAVACFLAGS := -Xlint
+
+# Services that will be built as part of services.jar
+# These should map to directory names relative to this
+# Android.mk.
+services := \
+ core \
+ accessibility \
+ appwidget \
+ backup \
+ devicepolicy \
+ print \
+ usb
+
+# The convention is to name each service module 'services.$(module_name)'
+LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
include $(BUILD_JAVA_LIBRARY)
@@ -39,7 +49,16 @@
include $(BUILD_SHARED_LIBRARY)
+# =============================================================
+
ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call all-makefiles-under, $(LOCAL_PATH))
+# A full make is happening, so make everything.
+include $(call all-makefiles-under,$(LOCAL_PATH))
+else
+# If we ran an mm[m] command, we still want to build the individual
+# services that we depend on. This differs from the above condition
+# by only including service makefiles and not any tests or other
+# modules.
+include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services))
endif
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 43e1f12..959d4a9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2722,7 +2722,8 @@
| AccessibilityNodeInfo.ACTION_SET_SELECTION
| AccessibilityNodeInfo.ACTION_EXPAND
| AccessibilityNodeInfo.ACTION_COLLAPSE
- | AccessibilityNodeInfo.ACTION_DISMISS;
+ | AccessibilityNodeInfo.ACTION_DISMISS
+ | AccessibilityNodeInfo.ACTION_SET_TEXT;
private static final int RETRIEVAL_ALLOWING_EVENT_TYPES =
AccessibilityEvent.TYPE_VIEW_CLICKED
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 5d86b38..e534a88 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -673,12 +673,19 @@
}
@Override
- public void setTime(long millis) {
+ public boolean setTime(long millis) {
getContext().enforceCallingOrSelfPermission(
"android.permission.SET_TIME",
"setTime");
- SystemClock.setCurrentTimeMillis(millis);
+ if (mNativeData == 0) {
+ Slog.w(TAG, "Not setting time since no alarm driver is available.");
+ return false;
+ }
+
+ synchronized (mLock) {
+ return setKernelTime(mNativeData, millis) == 0;
+ }
}
@Override
@@ -1063,6 +1070,7 @@
private native void close(long nativeData);
private native void set(long nativeData, int type, long seconds, long nanoseconds);
private native int waitForAlarm(long nativeData);
+ private native int setKernelTime(long nativeData, long millis);
private native int setKernelTimezone(long nativeData, int minuteswest);
void triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index 3fb006b..fc4838c 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -114,12 +114,11 @@
// Describes how bitmaps are placed in the atlas. Each bitmap is
// represented by several entries in the array:
- // int0: SkBitmap*, the native bitmap object
- // int1: x position
- // int2: y position
- // int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
- // NOTE: This will need to be handled differently to support 64 bit pointers
- private int[] mAtlasMap;
+ // long0: SkBitmap*, the native bitmap object
+ // long1: x position
+ // long2: y position
+ // long3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+ private long[] mAtlasMap;
/**
* Creates a new service. Upon creating, the service will gather the list of
@@ -196,7 +195,7 @@
private final ArrayList<Bitmap> mBitmaps;
private final int mPixelCount;
- private int mNativeBitmap;
+ private long mNativeBitmap;
// Used for debugging only
private Bitmap mAtlasBitmap;
@@ -260,8 +259,8 @@
final Atlas.Entry entry = new Atlas.Entry();
- mAtlasMap = new int[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
- int[] atlasMap = mAtlasMap;
+ mAtlasMap = new long[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
+ long[] atlasMap = mAtlasMap;
int mapIndex = 0;
boolean result = false;
@@ -288,8 +287,7 @@
}
canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
canvas.restore();
- // TODO: Change mAtlasMap to long[] to support 64-bit systems
- atlasMap[mapIndex++] = (int) bitmap.mNativeBitmap;
+ atlasMap[mapIndex++] = bitmap.mNativeBitmap;
atlasMap[mapIndex++] = entry.x;
atlasMap[mapIndex++] = entry.y;
atlasMap[mapIndex++] = entry.rotated ? 1 : 0;
@@ -365,9 +363,9 @@
}
}
- private static native int nAcquireAtlasCanvas(Canvas canvas, int width, int height);
- private static native void nReleaseAtlasCanvas(Canvas canvas, int bitmap);
- private static native boolean nUploadAtlas(GraphicBuffer buffer, int bitmap);
+ private static native long nAcquireAtlasCanvas(Canvas canvas, int width, int height);
+ private static native void nReleaseAtlasCanvas(Canvas canvas, long bitmap);
+ private static native boolean nUploadAtlas(GraphicBuffer buffer, long bitmap);
@Override
public boolean isCompatible(int ppid) {
@@ -380,7 +378,7 @@
}
@Override
- public int[] getMap() throws RemoteException {
+ public long[] getMap() throws RemoteException {
return mAtlasReady.get() ? mAtlasMap : null;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 9349730..36907ed 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -33,6 +33,7 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -44,7 +45,9 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -169,9 +172,9 @@
private static final String TAG = "ConnectivityService";
private static final boolean DBG = true;
- private static final boolean VDBG = true;
+ private static final boolean VDBG = false;
- private static final boolean LOGD_RULES = true;
+ private static final boolean LOGD_RULES = false;
// TODO: create better separation between radio types and network types
@@ -414,6 +417,8 @@
private SettingsObserver mSettingsObserver;
+ private AppOpsManager mAppOpsManager;
+
NetworkConfig[] mNetConfigs;
int mNetworksDefined;
@@ -697,6 +702,8 @@
filter = new IntentFilter();
filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
mContext.registerReceiver(mProvisioningReceiver, filter);
+
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
/**
@@ -1531,6 +1538,40 @@
}
/**
+ * Check if the address falls into any of currently running VPN's route's.
+ */
+ private boolean isAddressUnderVpn(InetAddress address) {
+ synchronized (mVpns) {
+ synchronized (mRoutesLock) {
+ int uid = UserHandle.getCallingUserId();
+ Vpn vpn = mVpns.get(uid);
+ if (vpn == null) {
+ return false;
+ }
+
+ // Check if an exemption exists for this address.
+ for (LinkAddress destination : mExemptAddresses) {
+ if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) {
+ continue;
+ }
+
+ int prefix = destination.getNetworkPrefixLength();
+ InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix);
+ InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(),
+ prefix);
+
+ if (addrMasked.equals(destMasked)) {
+ return false;
+ }
+ }
+
+ // Finally check if the address is covered by the VPN.
+ return vpn.isAddressCovered(address);
+ }
+ }
+ }
+
+ /**
* @deprecated use requestRouteToHostAddress instead
*
* Ensure that a network route exists to deliver traffic to the specified
@@ -1541,14 +1582,14 @@
* desired
* @return {@code true} on success, {@code false} on failure
*/
- public boolean requestRouteToHost(int networkType, int hostAddress) {
+ public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) {
InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
if (inetAddress == null) {
return false;
}
- return requestRouteToHostAddress(networkType, inetAddress.getAddress());
+ return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName);
}
/**
@@ -1560,11 +1601,40 @@
* desired
* @return {@code true} on success, {@code false} on failure
*/
- public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
+ public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress,
+ String packageName) {
enforceChangePermission();
if (mProtectedNetworks.contains(networkType)) {
enforceConnectivityInternalPermission();
}
+ boolean exempt;
+ InetAddress addr;
+ try {
+ addr = InetAddress.getByAddress(hostAddress);
+ } catch (UnknownHostException e) {
+ if (DBG) log("requestRouteToHostAddress got " + e.toString());
+ return false;
+ }
+ // System apps may request routes bypassing the VPN to keep other networks working.
+ if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+ exempt = true;
+ } else {
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+ try {
+ ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName,
+ 0);
+ exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("Failed to find calling package details", e);
+ }
+ }
+
+ // Non-exempt routeToHost's can only be added if the host is not covered by the VPN.
+ // This can be either because the VPN's routes do not cover the destination or a
+ // system application added an exemption that covers this destination.
+ if (!exempt && isAddressUnderVpn(addr)) {
+ return false;
+ }
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
@@ -1591,18 +1661,13 @@
}
final long token = Binder.clearCallingIdentity();
try {
- InetAddress addr = InetAddress.getByAddress(hostAddress);
LinkProperties lp = tracker.getLinkProperties();
- boolean ok = addRouteToAddress(lp, addr, EXEMPT);
+ boolean ok = addRouteToAddress(lp, addr, exempt);
if (DBG) log("requestRouteToHostAddress ok=" + ok);
return ok;
- } catch (UnknownHostException e) {
- if (DBG) log("requestRouteToHostAddress got " + e.toString());
} finally {
Binder.restoreCallingIdentity(token);
}
- if (DBG) log("requestRouteToHostAddress X bottom return false");
- return false;
}
private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
@@ -2352,7 +2417,7 @@
if (ConnectivityManager.isNetworkTypeMobile(type)) {
timeout = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
- 0);
+ 5);
// Canonicalize mobile network type
type = ConnectivityManager.TYPE_MOBILE;
} else if (ConnectivityManager.TYPE_WIFI == type) {
@@ -2632,7 +2697,7 @@
final int mtu = nt.getLinkProperties().getMtu();
if (mtu < 68 || mtu > 10000) {
- loge("Unexpected mtu value: " + nt);
+ loge("Unexpected mtu value: " + mtu + ", " + nt);
return;
}
@@ -2669,6 +2734,15 @@
}
setBufferSize(bufferSizes);
}
+
+ final String defaultRwndKey = "net.tcp.default_init_rwnd";
+ int defaultRwndValue = SystemProperties.getInt(defaultRwndKey, 0);
+ Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TCP_DEFAULT_INIT_RWND, defaultRwndValue);
+ final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd";
+ if (rwndValue != 0) {
+ SystemProperties.set(sysctlKey, rwndValue.toString());
+ }
}
/**
@@ -4325,7 +4399,7 @@
// Make a route to host so we check the specific interface.
if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI,
- hostAddr.getAddress())) {
+ hostAddr.getAddress(), null)) {
// Wait a short time to be sure the route is established ??
log("isMobileOk:"
+ " wait to establish route to hostAddr=" + hostAddr);
@@ -4495,7 +4569,6 @@
* @param seconds
*/
private static void sleep(int seconds) {
- log("XXXXX sleeping for " + seconds + " sec");
long stopTime = System.nanoTime() + (seconds * 1000000000);
long sleepTime;
while ((sleepTime = stopTime - System.nanoTime()) > 0) {
@@ -4504,7 +4577,6 @@
} catch (InterruptedException ignored) {
}
}
- log("XXXXX returning from sleep");
}
private static void log(String s) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index eebd1c5..fc68205 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -73,6 +73,9 @@
import com.android.server.location.LocationFudger;
import com.android.server.location.LocationProviderInterface;
import com.android.server.location.LocationProviderProxy;
+import com.android.server.location.LocationRequestStatistics;
+import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
+import com.android.server.location.LocationRequestStatistics.PackageStatistics;
import com.android.server.location.MockProvider;
import com.android.server.location.PassiveProvider;
@@ -178,6 +181,8 @@
private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
new HashMap<String, ArrayList<UpdateRecord>>();
+ private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
+
// mapping from provider name to last known location
private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
@@ -568,7 +573,7 @@
if (isAllowedByCurrentUserSettingsLocked(updateRecord.mProvider)) {
requestingLocation = true;
LocationProviderInterface locationProvider
- = mProvidersByName.get(updateRecord.mProvider);
+ = mProvidersByName.get(updateRecord.mProvider);
ProviderProperties properties = locationProvider != null
? locationProvider.getProperties() : null;
if (properties != null
@@ -813,7 +818,7 @@
long identity = Binder.clearCallingIdentity();
receiver.decrementPendingBroadcastsLocked();
Binder.restoreCallingIdentity(identity);
- }
+ }
}
}
}
@@ -1288,13 +1293,18 @@
if (!records.contains(this)) {
records.add(this);
}
+
+ // Update statistics for historical location requests by package/provider
+ mRequestStatistics.startRequesting(
+ mReceiver.mPackageName, provider, request.getInterval());
}
/**
- * Method to be called when a record will no longer be used. Calling this multiple times
- * must have the same effect as calling it once.
+ * Method to be called when a record will no longer be used.
*/
void disposeLocked(boolean removeReceiver) {
+ mRequestStatistics.stopRequesting(mReceiver.mPackageName, mProvider);
+
// remove from mRecordsByProvider
ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
if (globalRecords != null) {
@@ -1541,6 +1551,7 @@
if (oldRecords != null) {
// Call dispose() on the obsolete update records.
for (UpdateRecord record : oldRecords.values()) {
+ // Update statistics for historical location requests by package/provider
record.disposeLocked(false);
}
// Accumulate providers
@@ -1762,7 +1773,7 @@
@Override
public ProviderProperties getProviderProperties(String provider) {
if (mProvidersByName.get(provider) == null) {
- return null;
+ return null;
}
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
@@ -1965,7 +1976,7 @@
// Fetch latest status update time
long newStatusUpdateTime = p.getStatusUpdateTime();
- // Get latest status
+ // Get latest status
Bundle extras = new Bundle();
int status = p.getStatus(extras);
@@ -2179,7 +2190,7 @@
}
if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
- PackageManager.PERMISSION_GRANTED) {
+ PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
}
}
@@ -2351,13 +2362,20 @@
for (Receiver receiver : mReceivers.values()) {
pw.println(" " + receiver);
}
- pw.println(" Records by Provider:");
+ pw.println(" Active Records by Provider:");
for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
pw.println(" " + entry.getKey() + ":");
for (UpdateRecord record : entry.getValue()) {
pw.println(" " + record);
}
}
+ pw.println(" Historical Records by Provider:");
+ for (Map.Entry<PackageProviderKey, PackageStatistics> entry
+ : mRequestStatistics.statistics.entrySet()) {
+ PackageProviderKey key = entry.getKey();
+ PackageStatistics stats = entry.getValue();
+ pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
+ }
pw.println(" Last Known Locations:");
for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
String provider = entry.getKey();
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index e6e4bca..607def6 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -73,13 +73,16 @@
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
+import org.apache.commons.codec.binary.Hex;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
@@ -91,6 +94,7 @@
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -189,6 +193,12 @@
public static final int FstrimCompleted = 700;
}
+ /** List of crypto types.
+ * These must match CRYPT_TYPE_XXX in cryptfs.h AND their
+ * corresponding commands in CommandListener.cpp */
+ public static final String[] CRYPTO_TYPES
+ = { "password", "default", "pattern", "pin" };
+
private Context mContext;
private NativeDaemonConnector mConnector;
@@ -388,18 +398,37 @@
}
class ShutdownCallBack extends UnmountCallBack {
- IMountShutdownObserver observer;
- ShutdownCallBack(String path, IMountShutdownObserver observer) {
+ MountShutdownLatch mMountShutdownLatch;
+ ShutdownCallBack(String path, final MountShutdownLatch mountShutdownLatch) {
super(path, true, false);
- this.observer = observer;
+ mMountShutdownLatch = mountShutdownLatch;
}
@Override
void handleFinished() {
int ret = doUnmountVolume(path, true, removeEncryption);
- if (observer != null) {
+ Slog.i(TAG, "Unmount completed: " + path + ", result code: " + ret);
+ mMountShutdownLatch.countDown();
+ }
+ }
+
+ static class MountShutdownLatch {
+ private IMountShutdownObserver mObserver;
+ private AtomicInteger mCount;
+
+ MountShutdownLatch(final IMountShutdownObserver observer, int count) {
+ mObserver = observer;
+ mCount = new AtomicInteger(count);
+ }
+
+ void countDown() {
+ boolean sendShutdown = false;
+ if (mCount.decrementAndGet() == 0) {
+ sendShutdown = true;
+ }
+ if (sendShutdown && mObserver != null) {
try {
- observer.onShutDownComplete(ret);
+ mObserver.onShutDownComplete(StorageResultCode.OperationSucceeded);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException when shutting down");
}
@@ -1427,6 +1456,10 @@
Slog.i(TAG, "Shutting down");
synchronized (mVolumesLock) {
+ // Get all volumes to be unmounted.
+ MountShutdownLatch mountShutdownLatch = new MountShutdownLatch(observer,
+ mVolumeStates.size());
+
for (String path : mVolumeStates.keySet()) {
String state = mVolumeStates.get(path);
@@ -1462,19 +1495,16 @@
if (state.equals(Environment.MEDIA_MOUNTED)) {
// Post a unmount message.
- ShutdownCallBack ucb = new ShutdownCallBack(path, observer);
+ ShutdownCallBack ucb = new ShutdownCallBack(path, mountShutdownLatch);
mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
} else if (observer != null) {
/*
- * Observer is waiting for onShutDownComplete when we are done.
- * Since nothing will be done send notification directly so shutdown
- * sequence can continue.
+ * Count down, since nothing will be done. The observer will be
+ * notified when we are done so shutdown sequence can continue.
*/
- try {
- observer.onShutDownComplete(StorageResultCode.OperationSucceeded);
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException when shutting down");
- }
+ mountShutdownLatch.countDown();
+ Slog.i(TAG, "Unmount completed: " + path +
+ ", result code: " + StorageResultCode.OperationSucceeded);
}
}
}
@@ -2036,6 +2066,14 @@
}
}
+ private String toHex(String password) {
+ if (password == null) {
+ return null;
+ }
+ byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
+ return new String(Hex.encodeHex(bytes));
+ }
+
@Override
public int decryptStorage(String password) {
if (TextUtils.isEmpty(password)) {
@@ -2053,7 +2091,7 @@
final NativeDaemonEvent event;
try {
- event = mConnector.execute("cryptfs", "checkpw", new SensitiveArg(password));
+ event = mConnector.execute("cryptfs", "checkpw", new SensitiveArg(toHex(password)));
final int code = Integer.parseInt(event.getMessage());
if (code == 0) {
@@ -2092,7 +2130,8 @@
}
try {
- mConnector.execute("cryptfs", "enablecrypto", "inplace", new SensitiveArg(password));
+ mConnector.execute("cryptfs", "enablecrypto", "inplace",
+ new SensitiveArg(toHex(password)));
} catch (NativeDaemonConnectorException e) {
// Encryption failed
return e.getCode();
@@ -2101,11 +2140,11 @@
return 0;
}
- public int changeEncryptionPassword(String password) {
- if (TextUtils.isEmpty(password)) {
- throw new IllegalArgumentException("password cannot be empty");
- }
-
+ /** Set the password for encrypting the master key.
+ * @param type One of the CRYPTO_TYPE_XXX consts defined in StorageManager.
+ * @param password The password to set.
+ */
+ public int changeEncryptionPassword(int type, String password) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.CRYPT_KEEPER,
"no permission to access the crypt keeper");
@@ -2117,7 +2156,8 @@
final NativeDaemonEvent event;
try {
- event = mConnector.execute("cryptfs", "changepw", new SensitiveArg(password));
+ event = mConnector.execute("cryptfs", "changepw", CRYPTO_TYPES[type],
+ new SensitiveArg(toHex(password)));
return Integer.parseInt(event.getMessage());
} catch (NativeDaemonConnectorException e) {
// Encryption failed
@@ -2150,7 +2190,7 @@
final NativeDaemonEvent event;
try {
- event = mConnector.execute("cryptfs", "verifypw", new SensitiveArg(password));
+ event = mConnector.execute("cryptfs", "verifypw", new SensitiveArg(toHex(password)));
Slog.i(TAG, "cryptfs verifypw => " + event.getMessage());
return Integer.parseInt(event.getMessage());
} catch (NativeDaemonConnectorException e) {
@@ -2159,6 +2199,29 @@
}
}
+ /**
+ * Get the type of encryption used to encrypt the master key.
+ * @return The type, one of the CRYPT_TYPE_XXX consts from StorageManager.
+ */
+ @Override
+ public int getPasswordType() throws RemoteException {
+
+ waitForReady();
+
+ final NativeDaemonEvent event;
+ try {
+ event = mConnector.execute("cryptfs", "getpwtype");
+ for (int i = 0; i < CRYPTO_TYPES.length; ++i) {
+ if (CRYPTO_TYPES[i].equals(event.getMessage()))
+ return i;
+ }
+
+ throw new IllegalStateException("unexpected return from cryptfs");
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
@Override
public int mkdirs(String callingPkg, String appPath) {
final int userId = UserHandle.getUserId(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index ad7ec99..74de577 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -20,6 +20,7 @@
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.NetworkStats.SET_DEFAULT;
+import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
@@ -82,6 +83,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
@@ -151,6 +153,8 @@
private final Handler mMainHandler = new Handler();
+ private IBatteryStats mBatteryStats;
+
private Thread mThread;
private CountDownLatch mConnectedSignal = new CountDownLatch(1);
@@ -226,6 +230,17 @@
if (DBG) Slog.d(TAG, "Prepared");
}
+ private IBatteryStats getBatteryStats() {
+ synchronized (this) {
+ if (mBatteryStats != null) {
+ return mBatteryStats;
+ }
+ mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
+ BatteryStats.SERVICE_NAME));
+ return mBatteryStats;
+ }
+ }
+
@Override
public void registerObserver(INetworkManagementEventObserver observer) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -323,6 +338,10 @@
* Notify our observers of a change in the data activity state of the interface
*/
private void notifyInterfaceClassActivity(String label, boolean active) {
+ try {
+ getBatteryStats().noteDataConnectionActive(label, active);
+ } catch (RemoteException e) {
+ }
final int length = mObservers.beginBroadcast();
for (int i = 0; i < length; i++) {
try {
@@ -359,8 +378,7 @@
if (mBandwidthControlEnabled) {
try {
- IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME))
- .noteNetworkStatsEnabled();
+ getBatteryStats().noteNetworkStatsEnabled();
} catch (RemoteException e) {
}
}
@@ -1022,6 +1040,15 @@
}
}
+ private List<InterfaceAddress> excludeLinkLocal(List<InterfaceAddress> addresses) {
+ ArrayList<InterfaceAddress> filtered = new ArrayList<InterfaceAddress>(addresses.size());
+ for (InterfaceAddress ia : addresses) {
+ if (!ia.getAddress().isLinkLocalAddress())
+ filtered.add(ia);
+ }
+ return filtered;
+ }
+
private void modifyNat(String action, String internalInterface, String externalInterface)
throws SocketException {
final Command cmd = new Command("nat", action, internalInterface, externalInterface);
@@ -1031,8 +1058,10 @@
if (internalNetworkInterface == null) {
cmd.appendArg("0");
} else {
- Collection<InterfaceAddress> interfaceAddresses = internalNetworkInterface
- .getInterfaceAddresses();
+ // Don't touch link-local routes, as link-local addresses aren't routable,
+ // kernel creates link-local routes on all interfaces automatically
+ List<InterfaceAddress> interfaceAddresses = excludeLinkLocal(
+ internalNetworkInterface.getInterfaceAddresses());
cmd.appendArg(interfaceAddresses.size());
for (InterfaceAddress ia : interfaceAddresses) {
InetAddress addr = NetworkUtils.getNetworkPart(
@@ -1192,6 +1221,8 @@
throw e.rethrowAsParcelableException();
}
mActiveIdleTimers.put(iface, new IdleTimerParams(timeout, label));
+ // Networks start up.
+ notifyInterfaceClassActivity(label, true);
}
}
@@ -1241,7 +1272,7 @@
public NetworkStats getNetworkStatsDetail() {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return mStatsFactory.readNetworkStatsDetail(UID_ALL);
+ return mStatsFactory.readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null);
} catch (IOException e) {
throw new IllegalStateException(e);
}
@@ -1402,7 +1433,7 @@
public NetworkStats getNetworkStatsUidDetail(int uid) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- return mStatsFactory.readNetworkStatsDetail(uid);
+ return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null);
} catch (IOException e) {
throw new IllegalStateException(e);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 699d79e..77f5182 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -37,6 +37,10 @@
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
import android.telephony.TelephonyManager;
+import android.telephony.DisconnectCause;
+import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
+import android.telephony.PreciseDisconnectCause;
import android.text.TextUtils;
import android.util.Slog;
@@ -125,6 +129,17 @@
private List<CellInfo> mCellInfo = null;
+ private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+
+ private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+
+ private int mBackgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+
+ private PreciseCallState mPreciseCallState = new PreciseCallState();
+
+ private PreciseDataConnectionState mPreciseDataConnectionState =
+ new PreciseDataConnectionState();
+
static final int PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
PhoneStateListener.LISTEN_CALL_STATE |
@@ -132,6 +147,10 @@
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;
+ static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
+ PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
+ PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;
+
private static final int MSG_USER_SWITCHED = 1;
private final Handler mHandler = new Handler() {
@@ -305,6 +324,21 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+ try {
+ r.callback.onPreciseCallStateChanged(mPreciseCallState);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+ if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+ try {
+ r.callback.onPreciseDataConnectionStateChanged(
+ mPreciseDataConnectionState);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -533,30 +567,47 @@
}
handleRemoveListLocked();
}
+ mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
+ apnType, apn, reason, linkProperties, "");
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+ try {
+ r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
apnType, linkProperties, linkCapabilities, roaming);
+ broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
+ linkProperties, "");
}
public void notifyDataConnectionFailed(String reason, String apnType) {
if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
}
- /*
- * This is commented out because there is no onDataConnectionFailed callback
- * in PhoneStateListener. There should be.
synchronized (mRecords) {
- mDataConnectionFailedReason = reason;
- final int N = mRecords.size();
- for (int i=N-1; i>=0; i--) {
- Record r = mRecords.get(i);
- if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) {
- // XXX
+ mPreciseDataConnectionState = new PreciseDataConnectionState(
+ TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ apnType, "", reason, null, "");
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+ try {
+ r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
}
}
+ handleRemoveListLocked();
}
- */
broadcastDataConnectionFailed(reason, apnType);
+ broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
}
public void notifyCellLocation(Bundle cellLocation) {
@@ -602,6 +653,81 @@
}
}
+ public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
+ int backgroundCallState) {
+ if (!checkNotifyPermission("notifyPreciseCallState()")) {
+ return;
+ }
+ synchronized (mRecords) {
+ mRingingCallState = ringingCallState;
+ mForegroundCallState = foregroundCallState;
+ mBackgroundCallState = backgroundCallState;
+ mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
+ backgroundCallState,
+ DisconnectCause.NOT_VALID,
+ PreciseDisconnectCause.NOT_VALID);
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+ try {
+ r.callback.onPreciseCallStateChanged(mPreciseCallState);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
+ DisconnectCause.NOT_VALID,
+ PreciseDisconnectCause.NOT_VALID);
+ }
+
+ public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) {
+ if (!checkNotifyPermission("notifyDisconnectCause()")) {
+ return;
+ }
+ synchronized (mRecords) {
+ mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
+ mBackgroundCallState, disconnectCause, preciseDisconnectCause);
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
+ try {
+ r.callback.onPreciseCallStateChanged(mPreciseCallState);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState,
+ mBackgroundCallState, disconnectCause, preciseDisconnectCause);
+ }
+
+ public void notifyPreciseDataConnectionFailed(String reason, String apnType,
+ String apn, String failCause) {
+ if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
+ return;
+ }
+ synchronized (mRecords) {
+ mPreciseDataConnectionState = new PreciseDataConnectionState(
+ TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
+ apnType, apn, reason, null, failCause);
+ for (Record r : mRecords) {
+ if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
+ try {
+ r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ }
+ handleRemoveListLocked();
+ }
+ broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -738,6 +864,33 @@
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
+ int backgroundCallState, int disconnectCause, int preciseDisconnectCause) {
+ Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
+ intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
+ intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
+ intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
+ intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
+ intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE);
+ }
+
+ private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
+ String apnType, String apn, String reason, LinkProperties linkProperties, String failCause) {
+ Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
+ intent.putExtra(PhoneConstants.STATE_KEY, state);
+ intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
+ if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
+ if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
+ if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
+ if (linkProperties != null) intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
+ if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);
+
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE);
+ }
+
private boolean checkNotifyPermission(String method) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED) {
@@ -766,6 +919,12 @@
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PHONE_STATE, null);
}
+
+ if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);
+
+ }
}
private void handleRemoveListLocked() {
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index aa9849e..f587ccc 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -863,6 +863,7 @@
"User cannot modify accounts");
} catch (RemoteException re) {
}
+ return;
}
long identityToken = clearCallingIdentity();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
old mode 100644
new mode 100755
index be2df04..a845127
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -204,6 +204,7 @@
Slog.i(TAG, "Waited long enough for: " + r);
mStartingBackground.remove(i);
N--;
+ i--;
}
}
while (mDelayedStartList.size() > 0
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 77bb1a9..922cef4 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1235,12 +1235,14 @@
mUndrawnActivitiesBelowTopTranslucent.clear();
mHandler.removeMessages(TRANSLUCENT_TIMEOUT_MSG);
- if (waitingActivity != null && waitingActivity.app != null &&
- waitingActivity.app.thread != null) {
- try {
- waitingActivity.app.thread.scheduleTranslucentConversionComplete(
- waitingActivity.appToken, r != null);
- } catch (RemoteException e) {
+ if (waitingActivity != null) {
+ mWindowManager.setWindowOpaque(waitingActivity.appToken, false);
+ if (waitingActivity.app != null && waitingActivity.app.thread != null) {
+ try {
+ waitingActivity.app.thread.scheduleTranslucentConversionComplete(
+ waitingActivity.appToken, r != null);
+ } catch (RemoteException e) {
+ }
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6ed30d9..3a837e8 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1376,8 +1376,15 @@
void setFocusedStack(ActivityRecord r) {
if (r != null) {
- final boolean isHomeActivity =
- !r.isApplicationActivity() || (r.task != null && !r.task.isApplicationTask());
+ final TaskRecord task = r.task;
+ boolean isHomeActivity = !r.isApplicationActivity();
+ if (!isHomeActivity && task != null) {
+ isHomeActivity = !task.isApplicationTask();
+ }
+ if (!isHomeActivity && task != null) {
+ final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
+ isHomeActivity = parent != null && parent.isHomeActivity();
+ }
moveHomeStack(isHomeActivity);
}
}
@@ -2059,17 +2066,21 @@
if (targetStack == null) {
targetStack = getFocusedStack();
}
+ // Do targetStack first.
boolean result = false;
+ if (isFrontStack(targetStack)) {
+ result = targetStack.resumeTopActivityLocked(target, targetOptions);
+ }
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
+ if (stack == targetStack) {
+ // Already started above.
+ continue;
+ }
if (isFrontStack(stack)) {
- if (stack == targetStack) {
- result = stack.resumeTopActivityLocked(target, targetOptions);
- } else {
- stack.resumeTopActivityLocked(null);
- }
+ stack.resumeTopActivityLocked(null);
}
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 8a29ac7..059aa2b 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -230,7 +230,14 @@
mStats.noteUserActivityLocked(uid, event);
}
}
-
+
+ public void noteDataConnectionActive(String label, boolean active) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteDataConnectionActive(label, active);
+ }
+ }
+
public void notePhoneOn() {
enforceCallingPermission();
synchronized (mStats) {
@@ -330,6 +337,13 @@
}
}
+ public void noteWifiState(int wifiState, String accessPoint) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteWifiStateLocked(wifiState, accessPoint);
+ }
+ }
+
public void noteBluetoothOn() {
enforceCallingPermission();
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -373,6 +387,13 @@
}
}
+ public void noteBluetoothState(int bluetoothState) {
+ enforceCallingPermission();
+ synchronized (mStats) {
+ mStats.noteBluetoothStateLocked(bluetoothState);
+ }
+ }
+
public void noteFullWifiLockAcquired(int uid) {
enforceCallingPermission();
synchronized (mStats) {
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 207d630..ec500c2 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -1,3 +1,19 @@
+/*
+ * 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 java.io.File;
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 5971737..b233943 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -470,6 +470,7 @@
mTetheredNotification.defaults &= ~Notification.DEFAULT_SOUND;
mTetheredNotification.flags = Notification.FLAG_ONGOING_EVENT;
mTetheredNotification.tickerText = title;
+ mTetheredNotification.visibility = Notification.VISIBILITY_PUBLIC;
mTetheredNotification.setLatestEventInfo(mContext, title, message, pi);
notificationManager.notifyAsUser(null, mTetheredNotification.icon,
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index d87387f..af08d57 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -44,6 +44,7 @@
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.NetworkInfo;
+import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.NetworkInfo.DetailedState;
import android.os.Binder;
@@ -74,6 +75,7 @@
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.Inet4Address;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
@@ -430,6 +432,18 @@
return tun;
}
+ /**
+ * Check if a given address is covered by the VPN's routing rules.
+ */
+ public boolean isAddressCovered(InetAddress address) {
+ synchronized (Vpn.this) {
+ if (!isRunningLocked()) {
+ return false;
+ }
+ return RouteInfo.selectBestRoute(mConfig.routes, address) != null;
+ }
+ }
+
private boolean isRunningLocked() {
return mVpnUsers != null;
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 85ef33e..649b5c9 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -85,6 +85,7 @@
pw.println(" mToken=" + mCurrentDream.mToken);
pw.println(" mName=" + mCurrentDream.mName);
pw.println(" mIsTest=" + mCurrentDream.mIsTest);
+ pw.println(" mCanDoze=" + mCurrentDream.mCanDoze);
pw.println(" mUserId=" + mCurrentDream.mUserId);
pw.println(" mBound=" + mCurrentDream.mBound);
pw.println(" mService=" + mCurrentDream.mService);
@@ -94,15 +95,18 @@
}
}
- public void startDream(Binder token, ComponentName name, boolean isTest, int userId) {
+ public void startDream(Binder token, ComponentName name,
+ boolean isTest, boolean canDoze, int userId) {
stopDream();
// Close the notification shade. Don't need to send to all, but better to be explicit.
mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
- Slog.i(TAG, "Starting dream: name=" + name + ", isTest=" + isTest + ", userId=" + userId);
+ Slog.i(TAG, "Starting dream: name=" + name
+ + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, userId);
+ mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
try {
mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
@@ -140,7 +144,8 @@
final DreamRecord oldDream = mCurrentDream;
mCurrentDream = null;
Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", userId=" + oldDream.mUserId);
+ + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", userId=" + oldDream.mUserId);
mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
@@ -187,7 +192,7 @@
private void attach(IDreamService service) {
try {
service.asBinder().linkToDeath(mCurrentDream, 0);
- service.attach(mCurrentDream.mToken);
+ service.attach(mCurrentDream.mToken, mCurrentDream.mCanDoze);
} catch (RemoteException ex) {
Slog.e(TAG, "The dream service died unexpectedly.", ex);
stopDream();
@@ -213,6 +218,7 @@
public final Binder mToken;
public final ComponentName mName;
public final boolean mIsTest;
+ public final boolean mCanDoze;
public final int mUserId;
public boolean mBound;
@@ -221,10 +227,11 @@
public boolean mSentStartBroadcast;
public DreamRecord(Binder token, ComponentName name,
- boolean isTest, int userId) {
+ boolean isTest, boolean canDoze, int userId) {
mToken = token;
mName = name;
mIsTest = isTest;
+ mCanDoze = canDoze;
mUserId = userId;
}
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index f5acc4c..fd2f8a1 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -18,7 +18,9 @@
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
+import com.android.server.SystemService;
+import android.Manifest;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -28,14 +30,20 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDozeHardware;
import android.service.dreams.IDreamManager;
+import android.text.TextUtils;
import android.util.Slog;
import java.io.FileDescriptor;
@@ -50,7 +58,7 @@
*
* @hide
*/
-public final class DreamManagerService extends IDreamManager.Stub {
+public final class DreamManagerService extends SystemService {
private static final boolean DEBUG = false;
private static final String TAG = "DreamManagerService";
@@ -60,48 +68,65 @@
private final DreamHandler mHandler;
private final DreamController mController;
private final PowerManager mPowerManager;
+ private final PowerManager.WakeLock mDozeWakeLock;
+ private final McuHal mMcuHal; // synchronized on self
private Binder mCurrentDreamToken;
private ComponentName mCurrentDreamName;
private int mCurrentDreamUserId;
private boolean mCurrentDreamIsTest;
+ private boolean mCurrentDreamCanDoze;
+ private boolean mCurrentDreamIsDozing;
+ private DozeHardwareWrapper mCurrentDreamDozeHardware;
public DreamManagerService(Context context) {
+ super(context);
mContext = context;
mHandler = new DreamHandler(FgThread.get().getLooper());
mController = new DreamController(context, mHandler, mControllerListener);
mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- }
+ mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
- public void systemRunning() {
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (mLock) {
- stopDreamLocked();
- }
- }
- }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+ mMcuHal = McuHal.open();
+ if (mMcuHal != null) {
+ mMcuHal.reset();
+ }
}
@Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump DreamManager from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- return;
- }
+ public void onStart() {
+ publishBinderService(DreamService.DREAM_SERVICE, new BinderService());
+ publishLocalService(DreamManagerInternal.class, new LocalService());
+ }
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (mLock) {
+ stopDreamLocked();
+ }
+ }
+ }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
+ }
+ }
+
+ private void dumpInternal(PrintWriter pw) {
pw.println("DREAM MANAGER (dumpsys dreams)");
pw.println();
+ pw.println("mMcuHal=" + mMcuHal);
+ pw.println();
pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
pw.println("mCurrentDreamName=" + mCurrentDreamName);
pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
pw.println("mCurrentDreamIsTest=" + mCurrentDreamIsTest);
+ pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
+ pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
+ pw.println("mCurrentDreamDozeHardware=" + mCurrentDreamDozeHardware);
pw.println();
DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
@@ -112,174 +137,110 @@
}, pw, 200);
}
- @Override // Binder call
- public ComponentName[] getDreamComponents() {
- checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
- final int userId = UserHandle.getCallingUserId();
- final long ident = Binder.clearCallingIdentity();
- try {
- return getDreamComponentsForUser(userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override // Binder call
- public void setDreamComponents(ComponentName[] componentNames) {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
- final int userId = UserHandle.getCallingUserId();
- final long ident = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.SCREENSAVER_COMPONENTS,
- componentsToString(componentNames),
- userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override // Binder call
- public ComponentName getDefaultDreamComponent() {
- checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
- final int userId = UserHandle.getCallingUserId();
- final long ident = Binder.clearCallingIdentity();
- try {
- String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
- Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
- userId);
- return name == null ? null : ComponentName.unflattenFromString(name);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- @Override // Binder call
- public boolean isDreaming() {
- checkPermission(android.Manifest.permission.READ_DREAM_STATE);
-
+ private boolean isDreamingInternal() {
synchronized (mLock) {
return mCurrentDreamToken != null && !mCurrentDreamIsTest;
}
}
- @Override // Binder call
- public void dream() {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
- final long ident = Binder.clearCallingIdentity();
- try {
- // Ask the power manager to nap. It will eventually call back into
- // startDream() if/when it is appropriate to start dreaming.
- // Because napping could cause the screen to turn off immediately if the dream
- // cannot be started, we keep one eye open and gently poke user activity.
- long time = SystemClock.uptimeMillis();
- mPowerManager.userActivity(time, true /*noChangeLights*/);
- mPowerManager.nap(time);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ private void requestDreamInternal() {
+ // Ask the power manager to nap. It will eventually call back into
+ // startDream() if/when it is appropriate to start dreaming.
+ // Because napping could cause the screen to turn off immediately if the dream
+ // cannot be started, we keep one eye open and gently poke user activity.
+ long time = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(time, true /*noChangeLights*/);
+ mPowerManager.nap(time);
}
- @Override // Binder call
- public void testDream(ComponentName dream) {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+ private void requestAwakenInternal() {
+ // Treat an explicit request to awaken as user activity so that the
+ // device doesn't immediately go to sleep if the timeout expired,
+ // for example when being undocked.
+ long time = SystemClock.uptimeMillis();
+ mPowerManager.userActivity(time, false /*noChangeLights*/);
+ stopDreamInternal();
+ }
- if (dream == null) {
- throw new IllegalArgumentException("dream must not be null");
+ private void finishSelfInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream finished: " + token);
}
- final int callingUserId = UserHandle.getCallingUserId();
- final int currentUserId = ActivityManager.getCurrentUser();
- if (callingUserId != currentUserId) {
- // This check is inherently prone to races but at least it's something.
- Slog.w(TAG, "Aborted attempt to start a test dream while a different "
- + " user is active: callingUserId=" + callingUserId
- + ", currentUserId=" + currentUserId);
- return;
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- startDreamLocked(dream, true /*isTest*/, callingUserId);
+ // Note that a dream finishing and self-terminating is not
+ // itself considered user activity. If the dream is ending because
+ // the user interacted with the device then user activity will already
+ // have been poked so the device will stay awake a bit longer.
+ // If the dream is ending on its own for other reasons and no wake
+ // locks are held and the user activity timeout has expired then the
+ // device may simply go to sleep.
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token) {
+ stopDreamLocked();
}
- } finally {
- Binder.restoreCallingIdentity(ident);
}
}
- @Override // Binder call
- public void awaken() {
- checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
-
- final long ident = Binder.clearCallingIdentity();
- try {
- // Treat an explicit request to awaken as user activity so that the
- // device doesn't immediately go to sleep if the timeout expired,
- // for example when being undocked.
- long time = SystemClock.uptimeMillis();
- mPowerManager.userActivity(time, false /*noChangeLights*/);
- stopDream();
- } finally {
- Binder.restoreCallingIdentity(ident);
+ private void testDreamInternal(ComponentName dream, int userId) {
+ synchronized (mLock) {
+ startDreamLocked(dream, true /*isTest*/, false /*canDoze*/, userId);
}
}
- @Override // Binder call
- public void finishSelf(IBinder token) {
- // Requires no permission, called by Dream from an arbitrary process.
- if (token == null) {
- throw new IllegalArgumentException("token must not be null");
- }
-
- final long ident = Binder.clearCallingIdentity();
- try {
- if (DEBUG) {
- Slog.d(TAG, "Dream finished: " + token);
- }
-
- // Note that a dream finishing and self-terminating is not
- // itself considered user activity. If the dream is ending because
- // the user interacted with the device then user activity will already
- // have been poked so the device will stay awake a bit longer.
- // If the dream is ending on its own for other reasons and no wake
- // locks are held and the user activity timeout has expired then the
- // device may simply go to sleep.
- synchronized (mLock) {
- if (mCurrentDreamToken == token) {
- stopDreamLocked();
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- /**
- * Called by the power manager to start a dream.
- */
- public void startDream() {
- int userId = ActivityManager.getCurrentUser();
- ComponentName dream = chooseDreamForUser(userId);
+ private void startDreamInternal(boolean doze) {
+ final int userId = ActivityManager.getCurrentUser();
+ final ComponentName dream = doze ? getDozeComponent() : chooseDreamForUser(userId);
if (dream != null) {
synchronized (mLock) {
- startDreamLocked(dream, false /*isTest*/, userId);
+ startDreamLocked(dream, false /*isTest*/, doze, userId);
}
}
}
- /**
- * Called by the power manager to stop a dream.
- */
- public void stopDream() {
+ private void stopDreamInternal() {
synchronized (mLock) {
stopDreamLocked();
}
}
+ private void startDozingInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream requested to start dozing: " + token);
+ }
+
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && !mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = true;
+ mDozeWakeLock.acquire();
+ }
+ }
+ }
+
+ private void stopDozingInternal(IBinder token) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dream requested to stop dozing: " + token);
+ }
+
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ mDozeWakeLock.release();
+ }
+ }
+ }
+
+ private IDozeHardware getDozeHardwareInternal(IBinder token) {
+ synchronized (mLock) {
+ if (mCurrentDreamToken == token && mCurrentDreamCanDoze
+ && mCurrentDreamDozeHardware == null && mMcuHal != null) {
+ mCurrentDreamDozeHardware = new DozeHardwareWrapper();
+ return mCurrentDreamDozeHardware;
+ }
+ return null;
+ }
+ }
+
private ComponentName chooseDreamForUser(int userId) {
ComponentName[] dreams = getDreamComponentsForUser(userId);
return dreams != null && dreams.length != 0 ? dreams[0] : null;
@@ -305,7 +266,7 @@
// fallback to the default dream component if necessary
if (validComponents.isEmpty()) {
- ComponentName defaultDream = getDefaultDreamComponent();
+ ComponentName defaultDream = getDefaultDreamComponentForUser(userId);
if (defaultDream != null) {
Slog.w(TAG, "Falling back to default dream " + defaultDream);
validComponents.add(defaultDream);
@@ -314,6 +275,34 @@
return validComponents.toArray(new ComponentName[validComponents.size()]);
}
+ private void setDreamComponentsForUser(int userId, ComponentName[] componentNames) {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_COMPONENTS,
+ componentsToString(componentNames),
+ userId);
+ }
+
+ private ComponentName getDefaultDreamComponentForUser(int userId) {
+ String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+ userId);
+ return name == null ? null : ComponentName.unflattenFromString(name);
+ }
+
+ private ComponentName getDozeComponent() {
+ // Read the component from a system property to facilitate debugging.
+ // Note that for production devices, the dream should actually be declared in
+ // a config.xml resource.
+ String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
+ if (TextUtils.isEmpty(name)) {
+ // Read the component from a config.xml resource.
+ // The value should be specified in a resource overlay for the product.
+ name = mContext.getResources().getString(
+ com.android.internal.R.string.config_dozeComponent);
+ }
+ return TextUtils.isEmpty(name) ? null : ComponentName.unflattenFromString(name);
+ }
+
private boolean serviceExists(ComponentName name) {
try {
return name != null && mContext.getPackageManager().getServiceInfo(name, 0) != null;
@@ -323,9 +312,10 @@
}
private void startDreamLocked(final ComponentName name,
- final boolean isTest, final int userId) {
+ final boolean isTest, final boolean canDoze, final int userId) {
if (Objects.equal(mCurrentDreamName, name)
&& mCurrentDreamIsTest == isTest
+ && mCurrentDreamCanDoze == canDoze
&& mCurrentDreamUserId == userId) {
return;
}
@@ -338,12 +328,13 @@
mCurrentDreamToken = newToken;
mCurrentDreamName = name;
mCurrentDreamIsTest = isTest;
+ mCurrentDreamCanDoze = canDoze;
mCurrentDreamUserId = userId;
mHandler.post(new Runnable() {
@Override
public void run() {
- mController.startDream(newToken, name, isTest, userId);
+ mController.startDream(newToken, name, isTest, canDoze, userId);
}
});
}
@@ -367,7 +358,16 @@
mCurrentDreamToken = null;
mCurrentDreamName = null;
mCurrentDreamIsTest = false;
+ mCurrentDreamCanDoze = false;
mCurrentDreamUserId = 0;
+ if (mCurrentDreamIsDozing) {
+ mCurrentDreamIsDozing = false;
+ mDozeWakeLock.release();
+ }
+ if (mCurrentDreamDozeHardware != null) {
+ mCurrentDreamDozeHardware.release();
+ mCurrentDreamDozeHardware = null;
+ }
}
private void checkPermission(String permission) {
@@ -423,4 +423,233 @@
super(looper, null, true /*async*/);
}
}
+
+ private final class BinderService extends IDreamManager.Stub {
+ @Override // Binder call
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump DreamManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ dumpInternal(pw);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public ComponentName[] getDreamComponents() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDreamComponentsForUser(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void setDreamComponents(ComponentName[] componentNames) {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ setDreamComponentsForUser(userId, componentNames);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public ComponentName getDefaultDreamComponent() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final int userId = UserHandle.getCallingUserId();
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDefaultDreamComponentForUser(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public boolean isDreaming() {
+ checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return isDreamingInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void dream() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ requestDreamInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void testDream(ComponentName dream) {
+ if (dream == null) {
+ throw new IllegalArgumentException("dream must not be null");
+ }
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final int callingUserId = UserHandle.getCallingUserId();
+ final int currentUserId = ActivityManager.getCurrentUser();
+ if (callingUserId != currentUserId) {
+ // This check is inherently prone to races but at least it's something.
+ Slog.w(TAG, "Aborted attempt to start a test dream while a different "
+ + " user is active: callingUserId=" + callingUserId
+ + ", currentUserId=" + currentUserId);
+ return;
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ testDreamInternal(dream, callingUserId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void awaken() {
+ checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ requestAwakenInternal();
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void finishSelf(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ finishSelfInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void startDozing(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ startDozingInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public void stopDozing(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ stopDozingInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override // Binder call
+ public IDozeHardware getDozeHardware(IBinder token) {
+ // Requires no permission, called by Dream from an arbitrary process.
+ if (token == null) {
+ throw new IllegalArgumentException("token must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return getDozeHardwareInternal(token);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ private final class LocalService extends DreamManagerInternal {
+ @Override
+ public void startDream(boolean doze) {
+ startDreamInternal(doze);
+ }
+
+ @Override
+ public void stopDream() {
+ stopDreamInternal();
+ }
+
+ @Override
+ public boolean isDreaming() {
+ return isDreamingInternal();
+ }
+ }
+
+ private final class DozeHardwareWrapper extends IDozeHardware.Stub {
+ private boolean mReleased;
+
+ public void release() {
+ synchronized (mMcuHal) {
+ if (!mReleased) {
+ mReleased = true;
+ mMcuHal.reset();
+ }
+ }
+ }
+
+ @Override // Binder call
+ public byte[] sendMessage(String msg, byte[] arg) {
+ if (msg == null) {
+ throw new IllegalArgumentException("msg must not be null");
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMcuHal) {
+ if (mReleased) {
+ throw new IllegalStateException("This operation cannot be performed "
+ + "because the dream has ended.");
+ }
+ return mMcuHal.sendMessage(msg, arg);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/dreams/McuHal.java b/services/core/java/com/android/server/dreams/McuHal.java
new file mode 100644
index 0000000..1dc79c7
--- /dev/null
+++ b/services/core/java/com/android/server/dreams/McuHal.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.dreams;
+
+import android.service.dreams.DozeHardware;
+
+/**
+ * Provides access to the low-level microcontroller hardware abstraction layer.
+ */
+final class McuHal {
+ private final long mPtr;
+
+ private static native long nativeOpen();
+ private static native byte[] nativeSendMessage(long ptr, String msg, byte[] arg);
+
+ private McuHal(long ptr) {
+ mPtr = ptr;
+ }
+
+ public static McuHal open() {
+ long ptr = nativeOpen();
+ return ptr != 0 ? new McuHal(ptr) : null;
+ }
+
+ public void reset() {
+ sendMessage(DozeHardware.MSG_ENABLE_MCU, DozeHardware.VALUE_OFF);
+ }
+
+ public byte[] sendMessage(String msg, byte[] arg) {
+ return nativeSendMessage(mPtr, msg, arg);
+ }
+}
diff --git a/services/core/java/com/android/server/firewall/IntentFirewall.java b/services/core/java/com/android/server/firewall/IntentFirewall.java
index eb7a383..62114cd 100644
--- a/services/core/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/core/java/com/android/server/firewall/IntentFirewall.java
@@ -95,6 +95,7 @@
CategoryFilter.FACTORY,
SenderFilter.FACTORY,
+ SenderPackageFilter.FACTORY,
SenderPermissionFilter.FACTORY,
PortFilter.FACTORY
};
diff --git a/services/core/java/com/android/server/firewall/SenderPackageFilter.java b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
new file mode 100644
index 0000000..ec9b5de
--- /dev/null
+++ b/services/core/java/com/android/server/firewall/SenderPackageFilter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.firewall;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public class SenderPackageFilter implements Filter {
+ private static final String ATTR_NAME = "name";
+
+ public final String mPackageName;
+
+ public SenderPackageFilter(String packageName) {
+ mPackageName = packageName;
+ }
+
+ @Override
+ public boolean matches(IntentFirewall ifw, ComponentName resolvedComponent, Intent intent,
+ int callerUid, int callerPid, String resolvedType, int receivingUid) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+
+ int packageUid = -1;
+ try {
+ packageUid = pm.getPackageUid(mPackageName, UserHandle.USER_OWNER);
+ } catch (RemoteException ex) {
+ // handled below
+ }
+
+ if (packageUid == -1) {
+ return false;
+ }
+
+ return UserHandle.isSameApp(packageUid, callerUid);
+ }
+
+ public static final FilterFactory FACTORY = new FilterFactory("sender-package") {
+ @Override
+ public Filter newFilter(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String packageName = parser.getAttributeValue(null, ATTR_NAME);
+
+ if (packageName == null) {
+ throw new XmlPullParserException(
+ "A package name must be specified.", parser, null);
+ }
+
+ return new SenderPackageFilter(packageName);
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3aa3851..e49382e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1366,8 +1366,9 @@
}
// Native callback.
- private int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ private int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+ return mWindowManagerCallbacks.interceptMotionBeforeQueueingWhenScreenOff(
+ whenNanos, policyFlags);
}
// Native callback.
@@ -1527,7 +1528,7 @@
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags);
public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);
diff --git a/services/core/java/com/android/server/location/LocationRequestStatistics.java b/services/core/java/com/android/server/location/LocationRequestStatistics.java
new file mode 100644
index 0000000..85231bb
--- /dev/null
+++ b/services/core/java/com/android/server/location/LocationRequestStatistics.java
@@ -0,0 +1,205 @@
+package com.android.server.location;
+
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * Holds statistics for location requests (active requests by provider).
+ *
+ * <p>Must be externally synchronized.
+ */
+public class LocationRequestStatistics {
+ private static final String TAG = "LocationStats";
+
+ // Maps package name nad provider to location request statistics.
+ public final HashMap<PackageProviderKey, PackageStatistics> statistics
+ = new HashMap<PackageProviderKey, PackageStatistics>();
+
+ /**
+ * Signals that a package has started requesting locations.
+ *
+ * @param packageName Name of package that has requested locations.
+ * @param providerName Name of provider that is requested (e.g. "gps").
+ * @param intervalMs The interval that is requested in ms.
+ */
+ public void startRequesting(String packageName, String providerName, long intervalMs) {
+ PackageProviderKey key = new PackageProviderKey(packageName, providerName);
+ PackageStatistics stats = statistics.get(key);
+ if (stats == null) {
+ stats = new PackageStatistics();
+ statistics.put(key, stats);
+ }
+ stats.startRequesting(intervalMs);
+ }
+
+ /**
+ * Signals that a package has stopped requesting locations.
+ *
+ * @param packageName Name of package that has stopped requesting locations.
+ * @param providerName Provider that is no longer being requested.
+ */
+ public void stopRequesting(String packageName, String providerName) {
+ PackageProviderKey key = new PackageProviderKey(packageName, providerName);
+ PackageStatistics stats = statistics.get(key);
+ if (stats != null) {
+ stats.stopRequesting();
+ } else {
+ // This shouldn't be a possible code path.
+ Log.e(TAG, "Couldn't find package statistics when removing location request.");
+ }
+ }
+
+ /**
+ * A key that holds both package and provider names.
+ */
+ public static class PackageProviderKey {
+ /**
+ * Name of package requesting location.
+ */
+ public final String packageName;
+ /**
+ * Name of provider being requested (e.g. "gps").
+ */
+ public final String providerName;
+
+ public PackageProviderKey(String packageName, String providerName) {
+ this.packageName = packageName;
+ this.providerName = providerName;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof PackageProviderKey)) {
+ return false;
+ }
+
+ PackageProviderKey otherKey = (PackageProviderKey) other;
+ return packageName.equals(otherKey.packageName)
+ && providerName.equals(otherKey.providerName);
+ }
+
+ @Override
+ public int hashCode() {
+ return packageName.hashCode() + 31 * providerName.hashCode();
+ }
+ }
+
+ /**
+ * Usage statistics for a package/provider pair.
+ */
+ public static class PackageStatistics {
+ // Time when this package first requested location.
+ private final long mInitialElapsedTimeMs;
+ // Number of active location requests this package currently has.
+ private int mNumActiveRequests;
+ // Time when this package most recently went from not requesting location to requesting.
+ private long mLastActivitationElapsedTimeMs;
+ // The fastest interval this package has ever requested.
+ private long mFastestIntervalMs;
+ // The slowest interval this package has ever requested.
+ private long mSlowestIntervalMs;
+ // The total time this app has requested location (not including currently running requests).
+ private long mTotalDurationMs;
+
+ private PackageStatistics() {
+ mInitialElapsedTimeMs = SystemClock.elapsedRealtime();
+ mNumActiveRequests = 0;
+ mTotalDurationMs = 0;
+ mFastestIntervalMs = Long.MAX_VALUE;
+ mSlowestIntervalMs = 0;
+ }
+
+ private void startRequesting(long intervalMs) {
+ if (mNumActiveRequests == 0) {
+ mLastActivitationElapsedTimeMs = SystemClock.elapsedRealtime();
+ }
+
+ if (intervalMs < mFastestIntervalMs) {
+ mFastestIntervalMs = intervalMs;
+ }
+
+ if (intervalMs > mSlowestIntervalMs) {
+ mSlowestIntervalMs = intervalMs;
+ }
+
+ mNumActiveRequests++;
+ }
+
+ private void stopRequesting() {
+ if (mNumActiveRequests <= 0) {
+ // Shouldn't be a possible code path
+ Log.e(TAG, "Reference counting corrupted in usage statistics.");
+ return;
+ }
+
+ mNumActiveRequests--;
+ if (mNumActiveRequests == 0) {
+ long lastDurationMs
+ = SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
+ mTotalDurationMs += lastDurationMs;
+ }
+ }
+
+ /**
+ * Returns the duration that this request has been active.
+ */
+ public long getDurationMs() {
+ long currentDurationMs = mTotalDurationMs;
+ if (mNumActiveRequests > 0) {
+ currentDurationMs
+ += SystemClock.elapsedRealtime() - mLastActivitationElapsedTimeMs;
+ }
+ return currentDurationMs;
+ }
+
+ /**
+ * Returns the time since the initial request in ms.
+ */
+ public long getTimeSinceFirstRequestMs() {
+ return SystemClock.elapsedRealtime() - mInitialElapsedTimeMs;
+ }
+
+ /**
+ * Returns the fastest interval that has been tracked.
+ */
+ public long getFastestIntervalMs() {
+ return mFastestIntervalMs;
+ }
+
+ /**
+ * Returns the slowest interval that has been tracked.
+ */
+ public long getSlowestIntervalMs() {
+ return mSlowestIntervalMs;
+ }
+
+ /**
+ * Returns true if a request is active for these tracked statistics.
+ */
+ public boolean isActive() {
+ return mNumActiveRequests > 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder();
+ if (mFastestIntervalMs == mSlowestIntervalMs) {
+ s.append("Interval ").append(mFastestIntervalMs / 1000).append(" seconds");
+ } else {
+ s.append("Min interval ").append(mFastestIntervalMs / 1000).append(" seconds");
+ s.append(": Max interval ").append(mSlowestIntervalMs / 1000).append(" seconds");
+ }
+ s.append(": Duration requested ")
+ .append((getDurationMs() / 1000) / 60)
+ .append(" out of the last ")
+ .append((getTimeSinceFirstRequestMs() / 1000) / 60)
+ .append(" minutes");
+ if (isActive()) {
+ s.append(": Currently active");
+ }
+ return s.toString();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
new file mode 100644
index 0000000..0d3fa84
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.content.Intent;
+import android.media.IMediaController;
+import android.media.IMediaControllerCallback;
+import android.media.IMediaSession;
+import android.media.IMediaSessionCallback;
+import android.media.RemoteControlClient;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+
+/**
+ * This is the system implementation of a Session. Apps will interact with the
+ * MediaSession wrapper class instead.
+ */
+public class MediaSessionRecord implements IBinder.DeathRecipient {
+ private static final String TAG = "MediaSessionImpl";
+
+ private final int mPid;
+ private final String mPackageName;
+ private final String mTag;
+ private final ControllerStub mController;
+ private final SessionStub mSession;
+ private final SessionCb mSessionCb;
+ private final MediaSessionService mService;
+
+ private final ArrayList<IMediaControllerCallback> mSessionCallbacks =
+ new ArrayList<IMediaControllerCallback>();
+
+ private int mPlaybackState = RemoteControlClient.PLAYSTATE_NONE;
+
+ public MediaSessionRecord(int pid, String packageName, IMediaSessionCallback cb, String tag,
+ MediaSessionService service) {
+ mPid = pid;
+ mPackageName = packageName;
+ mTag = tag;
+ mController = new ControllerStub();
+ mSession = new SessionStub();
+ mSessionCb = new SessionCb(cb);
+ mService = service;
+ }
+
+ public IMediaSession getSessionBinder() {
+ return mSession;
+ }
+
+ public IMediaController getControllerBinder() {
+ return mController;
+ }
+
+ public void setPlaybackStateInternal(int state) {
+ mPlaybackState = state;
+ for (int i = mSessionCallbacks.size() - 1; i >= 0; i--) {
+ IMediaControllerCallback cb = mSessionCallbacks.get(i);
+ try {
+ cb.onPlaybackUpdate(state);
+ } catch (RemoteException e) {
+ Log.d(TAG, "SessionCallback object dead in setPlaybackState.", e);
+ mSessionCallbacks.remove(i);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ mService.sessionDied(this);
+ }
+
+ private void onDestroy() {
+ mService.destroySession(this);
+ }
+
+ private final class SessionStub extends IMediaSession.Stub {
+
+ @Override
+ public void setPlaybackState(int state) throws RemoteException {
+ setPlaybackStateInternal(state);
+ }
+
+ @Override
+ public void destroy() throws RemoteException {
+ onDestroy();
+ }
+
+ @Override
+ public void sendEvent(Bundle data) throws RemoteException {
+ }
+
+ @Override
+ public IMediaController getMediaSessionToken() throws RemoteException {
+ return mController;
+ }
+
+ @Override
+ public void setMetadata(Bundle metadata) throws RemoteException {
+ }
+
+ @Override
+ public void setRouteState(Bundle routeState) throws RemoteException {
+ }
+
+ @Override
+ public void setRoute(Bundle medaiRouteDescriptor) throws RemoteException {
+ }
+
+ }
+
+ class SessionCb {
+ private final IMediaSessionCallback mCb;
+
+ public SessionCb(IMediaSessionCallback cb) {
+ mCb = cb;
+ }
+
+ public void sendMediaButton(KeyEvent keyEvent) {
+ Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ try {
+ mCb.onMediaButton(mediaButtonIntent);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Controller object dead in sendMediaRequest.", e);
+ onDestroy();
+ }
+ }
+
+ public void sendCommand(String command, Bundle extras) {
+ try {
+ mCb.onCommand(command, extras);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Controller object dead in sendCommand.", e);
+ onDestroy();
+ }
+ }
+
+ public void registerCallbackListener(IMediaSessionCallback cb) {
+
+ }
+
+ }
+
+ class ControllerStub extends IMediaController.Stub {
+ /*
+ */
+ @Override
+ public void sendCommand(String command, Bundle extras) throws RemoteException {
+ mSessionCb.sendCommand(command, extras);
+ }
+
+ @Override
+ public void sendMediaButton(KeyEvent mediaButtonIntent) {
+ mSessionCb.sendMediaButton(mediaButtonIntent);
+ }
+
+ /*
+ */
+ @Override
+ public void registerCallbackListener(IMediaControllerCallback cb) throws RemoteException {
+ if (!mSessionCallbacks.contains(cb)) {
+ mSessionCallbacks.add(cb);
+ }
+ }
+
+ /*
+ */
+ @Override
+ public void unregisterCallbackListener(IMediaControllerCallback cb)
+ throws RemoteException {
+ mSessionCallbacks.remove(cb);
+ }
+
+ /*
+ */
+ @Override
+ public int getPlaybackState() throws RemoteException {
+ return mPlaybackState;
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
new file mode 100644
index 0000000..9c96c35
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import android.content.Context;
+import android.media.IMediaSession;
+import android.media.IMediaSessionCallback;
+import android.media.IMediaSessionManager;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.server.SystemService;
+
+import java.util.ArrayList;
+
+/**
+ * System implementation of MediaSessionManager
+ */
+public class MediaSessionService extends SystemService {
+ private static final String TAG = "MediaSessionService";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final SessionManagerImpl mSessionManagerImpl;
+
+ private final ArrayList<MediaSessionRecord> mSessions
+ = new ArrayList<MediaSessionRecord>();
+ private final Object mLock = new Object();
+
+ public MediaSessionService(Context context) {
+ super(context);
+ mSessionManagerImpl = new SessionManagerImpl();
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.MEDIA_SESSION_SERVICE, mSessionManagerImpl);
+ }
+
+ void sessionDied(MediaSessionRecord session) {
+ synchronized (mSessions) {
+ destroySessionLocked(session);
+ }
+ }
+
+ void destroySession(MediaSessionRecord session) {
+ synchronized (mSessions) {
+ destroySessionLocked(session);
+ }
+ }
+
+ private void destroySessionLocked(MediaSessionRecord session) {
+ mSessions.remove(session);
+ }
+
+ private void enforcePackageName(String packageName, int uid) {
+ if (TextUtils.isEmpty(packageName)) {
+ throw new IllegalArgumentException("packageName may not be empty");
+ }
+ String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+ final int packageCount = packages.length;
+ for (int i = 0; i < packageCount; i++) {
+ if (packageName.equals(packages[i])) {
+ return;
+ }
+ }
+ throw new IllegalArgumentException("packageName is not owned by the calling process");
+ }
+
+ private MediaSessionRecord createSessionInternal(int pid, String packageName,
+ IMediaSessionCallback cb, String tag) {
+ synchronized (mLock) {
+ return createSessionLocked(pid, packageName, cb, tag);
+ }
+ }
+
+ private MediaSessionRecord createSessionLocked(int pid, String packageName,
+ IMediaSessionCallback cb, String tag) {
+ final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this);
+ try {
+ cb.asBinder().linkToDeath(session, 0);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Media Session owner died prematurely.", e);
+ }
+ synchronized (mSessions) {
+ mSessions.add(session);
+ }
+ if (DEBUG) {
+ Log.d(TAG, "Created session for package " + packageName + " with tag " + tag);
+ }
+ return session;
+ }
+
+ class SessionManagerImpl extends IMediaSessionManager.Stub {
+ @Override
+ public IMediaSession createSession(String packageName, IMediaSessionCallback cb, String tag)
+ throws RemoteException {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ enforcePackageName(packageName, uid);
+ if (cb == null) {
+ throw new IllegalArgumentException("Controller callback cannot be null");
+ }
+ return createSessionInternal(pid, packageName, cb, tag).getSessionBinder();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerInternal.java b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
index 92ffdcc..b695b68 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerInternal.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerInternal.java
@@ -1,3 +1,19 @@
+/*
+ * 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.notification;
import android.app.Notification;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 01175bb..ab46dfe 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -725,7 +725,14 @@
// -- APIs to support listeners clicking/clearing notifications --
+ private void checkNullListener(INotificationListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null");
+ }
+ }
+
private NotificationListenerInfo checkListenerToken(INotificationListener listener) {
+ checkNullListener(listener);
final IBinder token = listener.asBinder();
final int N = mListeners.size();
for (int i=0; i<N; i++) {
@@ -1469,6 +1476,7 @@
public void registerListener(final INotificationListener listener,
final ComponentName component, final int userid) {
checkCallerIsSystem();
+ checkNullListener(listener);
registerListenerImpl(listener, component, userid);
}
@@ -1477,6 +1485,7 @@
*/
@Override
public void unregisterListener(INotificationListener listener, int userid) {
+ checkNullListener(listener);
// no need to check permissions; if your listener binder is in the list,
// that's proof that you had permission to add it in the first place
unregisterListenerImpl(listener, userid);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 6185e50..ad6eabd 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -221,6 +221,17 @@
return execute(builder.toString());
}
+ public int idmap(String targetApkPath, String overlayApkPath, int uid) {
+ StringBuilder builder = new StringBuilder("idmap");
+ builder.append(' ');
+ builder.append(targetApkPath);
+ builder.append(' ');
+ builder.append(overlayApkPath);
+ builder.append(' ');
+ builder.append(uid);
+ return execute(builder.toString());
+ }
+
public int movedex(String srcPath, String dstPath) {
StringBuilder builder = new StringBuilder("movedex");
builder.append(' ');
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6e90bf6..07a74cd 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -219,7 +219,8 @@
static final int SCAN_UPDATE_TIME = 1<<6;
static final int SCAN_DEFER_DEX = 1<<7;
static final int SCAN_BOOTING = 1<<8;
- static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<9;
+ static final int SCAN_TRUSTED_OVERLAY = 1<<9;
+ static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10;
static final int REMOVE_CHATTY = 1<<16;
@@ -260,9 +261,15 @@
private static final String LIB_DIR_NAME = "lib";
+ private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
+
static final String mTempContainerPrefix = "smdl2tmp";
final ServiceThread mHandlerThread;
+
+ private static final String IDMAP_PREFIX = "/data/resource-cache/";
+ private static final String IDMAP_SUFFIX = "@idmap";
+
final PackageHandler mHandler;
final int mSdkVersion = Build.VERSION.SDK_INT;
@@ -298,6 +305,9 @@
// This is the object monitoring the system app dir.
final FileObserver mVendorInstallObserver;
+ // This is the object monitoring the vendor overlay package dir.
+ final FileObserver mVendorOverlayInstallObserver;
+
// This is the object monitoring mAppInstallDir.
final FileObserver mAppInstallObserver;
@@ -344,6 +354,10 @@
final HashMap<String, PackageParser.Package> mPackages =
new HashMap<String, PackageParser.Package>();
+ // Tracks available target package names -> overlay package paths.
+ final HashMap<String, HashMap<String, PackageParser.Package>> mOverlays =
+ new HashMap<String, HashMap<String, PackageParser.Package>>();
+
final Settings mSettings;
boolean mRestoredSettings;
@@ -1279,6 +1293,17 @@
}
}
+ // Collect vendor overlay packages.
+ // (Do this before scanning any apps.)
+ // For security and version matching reason, only consider
+ // overlay packages if they reside in VENDOR_OVERLAY_DIR.
+ File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
+ mVendorOverlayInstallObserver = new AppDirObserver(
+ vendorOverlayDir.getPath(), OBSERVER_EVENTS, true, false);
+ mVendorOverlayInstallObserver.startWatching();
+ scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_TRUSTED_OVERLAY, 0);
+
// Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
@@ -2551,15 +2576,41 @@
}
}
+ /**
+ * Compares two sets of signatures. Returns:
+ * <br />
+ * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
+ * <br />
+ * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
+ */
static int compareSignatures(Signature[] s1, Signature[] s2) {
if (s1 == null) {
return s2 == null
? PackageManager.SIGNATURE_NEITHER_SIGNED
: PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
}
+
if (s2 == null) {
return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
}
+
+ if (s1.length != s2.length) {
+ return PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ // Since both signature sets are of size 1, we can compare without HashSets.
+ if (s1.length == 1) {
+ return s1[0].equals(s2[0]) ?
+ PackageManager.SIGNATURE_MATCH :
+ PackageManager.SIGNATURE_NO_MATCH;
+ }
+
HashSet<Signature> set1 = new HashSet<Signature>();
for (Signature sig : s1) {
set1.add(sig);
@@ -2726,6 +2777,63 @@
return null;
}
+ private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
+ int flags, List<ResolveInfo> query, boolean debug, int userId) {
+ final int N = query.size();
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .get(userId);
+ // Get the list of persistent preferred activities that handle the intent
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId)
+ : null;
+ if (pprefs != null && pprefs.size() > 0) {
+ final int M = pprefs.size();
+ for (int i=0; i<M; i++) {
+ final PersistentPreferredActivity ppa = pprefs.get(i);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+ + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
+ + "\n component=" + ppa.mComponent);
+ ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ }
+ final ActivityInfo ai = getActivityInfo(ppa.mComponent,
+ flags | PackageManager.GET_DISABLED_COMPONENTS, userId);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Found persistent preferred activity:");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ } else {
+ Slog.v(TAG, " null");
+ }
+ }
+ if (ai == null) {
+ // This previously registered persistent preferred activity
+ // component is no longer known. Ignore it and do NOT remove it.
+ continue;
+ }
+ for (int j=0; j<N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (!ri.activityInfo.applicationInfo.packageName
+ .equals(ai.applicationInfo.packageName)) {
+ continue;
+ }
+ if (!ri.activityInfo.name.equals(ai.name)) {
+ continue;
+ }
+ // Found a persistent preference that can handle the intent.
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Returning persistent preferred activity: " +
+ ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+ }
+ return ri;
+ }
+ }
+ }
+ return null;
+ }
+
ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
@@ -2736,6 +2844,16 @@
intent = intent.getSelector();
}
if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
+
+ // Try to find a matching persistent preferred activity.
+ ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
+ debug, userId);
+
+ // If a persistent preferred activity matched, use it.
+ if (pri != null) {
+ return pri;
+ }
+
PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
// Get the list of preferred activities that handle the intent
if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
@@ -3481,6 +3599,56 @@
return finalList;
}
+ private void createIdmapsForPackageLI(PackageParser.Package pkg) {
+ HashMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName);
+ if (overlays == null) {
+ Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages");
+ return;
+ }
+ for (PackageParser.Package opkg : overlays.values()) {
+ // Not much to do if idmap fails: we already logged the error
+ // and we certainly don't want to abort installation of pkg simply
+ // because an overlay didn't fit properly. For these reasons,
+ // ignore the return value of createIdmapForPackagePairLI.
+ createIdmapForPackagePairLI(pkg, opkg);
+ }
+ }
+
+ private boolean createIdmapForPackagePairLI(PackageParser.Package pkg,
+ PackageParser.Package opkg) {
+ if (!opkg.mTrustedOverlay) {
+ Slog.w(TAG, "Skipping target and overlay pair " + pkg.mScanPath + " and " +
+ opkg.mScanPath + ": overlay not trusted");
+ return false;
+ }
+ HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
+ if (overlaySet == null) {
+ Slog.e(TAG, "was about to create idmap for " + pkg.mScanPath + " and " +
+ opkg.mScanPath + " but target package has no known overlays");
+ return false;
+ }
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) {
+ Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath);
+ return false;
+ }
+ PackageParser.Package[] overlayArray =
+ overlaySet.values().toArray(new PackageParser.Package[0]);
+ Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() {
+ public int compare(PackageParser.Package p1, PackageParser.Package p2) {
+ return p1.mOverlayPriority - p2.mOverlayPriority;
+ }
+ };
+ Arrays.sort(overlayArray, cmp);
+
+ pkg.applicationInfo.resourceDirs = new String[overlayArray.length];
+ int i = 0;
+ for (PackageParser.Package p : overlayArray) {
+ pkg.applicationInfo.resourceDirs[i++] = p.applicationInfo.sourceDir;
+ }
+ return true;
+ }
+
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();
if (files == null) {
@@ -3578,7 +3746,7 @@
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
final PackageParser.Package pkg = pp.parsePackage(scanFile,
- scanPath, mMetrics, parseFlags);
+ scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
if (pkg == null) {
mLastScanError = pp.getParseError();
@@ -5095,6 +5263,29 @@
}
pkgSetting.setTimeStamp(scanFileTime);
+
+ // Create idmap files for pairs of (packages, overlay packages).
+ // Note: "android", ie framework-res.apk, is handled by native layers.
+ if (pkg.mOverlayTarget != null) {
+ // This is an overlay package.
+ if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
+ if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
+ mOverlays.put(pkg.mOverlayTarget,
+ new HashMap<String, PackageParser.Package>());
+ }
+ HashMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
+ map.put(pkg.packageName, pkg);
+ PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
+ if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
+ mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+ return null;
+ }
+ }
+ } else if (mOverlays.containsKey(pkg.packageName) &&
+ !pkg.packageName.equals("android")) {
+ // This is a regular package, with one or more known overlay packages.
+ createIdmapsForPackageLI(pkg);
+ }
}
return pkg;
@@ -10217,6 +10408,71 @@
}
@Override
+ public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
+ int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "addPersistentPreferredActivity can only be run by the system");
+ }
+ if (filter.countActions() == 0) {
+ Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
+ return;
+ }
+ synchronized (mPackages) {
+ Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId +
+ " :");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
+ new PersistentPreferredActivity(filter, activity));
+ mSettings.writePackageRestrictionsLPr(userId);
+ }
+ }
+
+ @Override
+ public void clearPackagePersistentPreferredActivities(String packageName, int userId) {
+ int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.SYSTEM_UID) {
+ throw new SecurityException(
+ "clearPackagePersistentPreferredActivities can only be run by the system");
+ }
+ ArrayList<PersistentPreferredActivity> removed = null;
+ boolean changed = false;
+ synchronized (mPackages) {
+ for (int i=0; i<mSettings.mPersistentPreferredActivities.size(); i++) {
+ final int thisUserId = mSettings.mPersistentPreferredActivities.keyAt(i);
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .valueAt(i);
+ if (userId != thisUserId) {
+ continue;
+ }
+ Iterator<PersistentPreferredActivity> it = ppir.filterIterator();
+ while (it.hasNext()) {
+ PersistentPreferredActivity ppa = it.next();
+ // Mark entry for removal only if it matches the package name.
+ if (ppa.mComponent.getPackageName().equals(packageName)) {
+ if (removed == null) {
+ removed = new ArrayList<PersistentPreferredActivity>();
+ }
+ removed.add(ppa);
+ }
+ }
+ if (removed != null) {
+ for (int j=0; j<removed.size(); j++) {
+ PersistentPreferredActivity ppa = removed.get(j);
+ ppir.removeFilter(ppa);
+ }
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ mSettings.writePackageRestrictionsLPr(userId);
+ }
+ }
+ }
+
+ @Override
public ComponentName getHomeActivities(List<ResolveInfo> allHomeCandidates) {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
new file mode 100644
index 0000000..4284a6d
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import java.io.IOException;
+
+class PersistentPreferredActivity extends IntentFilter {
+ private static final String ATTR_NAME = "name"; // component name
+ private static final String ATTR_FILTER = "filter"; // filter
+
+ private static final String TAG = "PersistentPreferredActivity";
+
+ private static final boolean DEBUG_FILTERS = false;
+
+ final ComponentName mComponent;
+
+ PersistentPreferredActivity(IntentFilter filter, ComponentName activity) {
+ super(filter);
+ mComponent = activity;
+ }
+
+ PersistentPreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
+ String shortComponent = parser.getAttributeValue(null, ATTR_NAME);
+ mComponent = ComponentName.unflattenFromString(shortComponent);
+ if (mComponent == null) {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Error in package manager settings <hard-preferred-activity>: " +
+ "Bad activity name " + shortComponent +
+ " at " + parser.getPositionDescription());
+ }
+ int outerDepth = parser.getDepth();
+ String tagName = parser.getName();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ tagName = parser.getName();
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ } else if (type == XmlPullParser.START_TAG) {
+ if (tagName.equals(ATTR_FILTER)) {
+ break;
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <hard-preferred-activity>: " + tagName +
+ " at " + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+ if (tagName.equals(ATTR_FILTER)) {
+ readFromXml(parser);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Missing element under <hard-preferred-activity>: filter at " +
+ parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+
+ public void writeToXml(XmlSerializer serializer) throws IOException {
+ serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
+ serializer.startTag(null, ATTR_FILTER);
+ super.writeToXml(serializer);
+ serializer.endTag(null, ATTR_FILTER);
+ }
+
+ @Override
+ public String toString() {
+ return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
+ + " " + mComponent.flattenToShortString() + "}";
+ }
+}
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
new file mode 100644
index 0000000..9c8a9bd
--- /dev/null
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import java.io.PrintWriter;
+
+import com.android.server.IntentResolver;
+
+public class PersistentPreferredIntentResolver
+ extends IntentResolver<PersistentPreferredActivity, PersistentPreferredActivity> {
+ @Override
+ protected PersistentPreferredActivity[] newArray(int size) {
+ return new PersistentPreferredActivity[size];
+ }
+
+ @Override
+ protected boolean isPackageForFilter(String packageName, PersistentPreferredActivity filter) {
+ return packageName.equals(filter.mComponent.getPackageName());
+ }
+}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e7c6446..9236bde 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -141,6 +141,11 @@
final SparseArray<PreferredIntentResolver> mPreferredActivities =
new SparseArray<PreferredIntentResolver>();
+ // The persistent preferred activities of the user's profile/device owner
+ // associated with particular intent filters.
+ final SparseArray<PersistentPreferredIntentResolver> mPersistentPreferredActivities =
+ new SparseArray<PersistentPreferredIntentResolver>();
+
final HashMap<String, SharedUserSetting> mSharedUsers =
new HashMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
@@ -776,6 +781,15 @@
return pir;
}
+ PersistentPreferredIntentResolver editPersistentPreferredActivitiesLPw(int userId) {
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ if (ppir == null) {
+ ppir = new PersistentPreferredIntentResolver();
+ mPersistentPreferredActivities.put(userId, ppir);
+ }
+ return ppir;
+ }
+
private File getUserPackagesStateFile(int userId) {
return new File(Environment.getUserSystemDirectory(userId), "package-restrictions.xml");
}
@@ -835,6 +849,27 @@
}
}
+ private void readPersistentPreferredActivitiesLPw(XmlPullParser parser, int userId)
+ throws XmlPullParserException, IOException {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals(TAG_ITEM)) {
+ PersistentPreferredActivity ppa = new PersistentPreferredActivity(parser);
+ editPersistentPreferredActivitiesLPw(userId).addFilter(ppa);
+ } else {
+ PackageManagerService.reportSettingsProblem(Log.WARN,
+ "Unknown element under <hard-preferred-activities>: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
void readPackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -961,6 +996,8 @@
enabledCaller, enabledComponents, disabledComponents);
} else if (tagName.equals("preferred-activities")) {
readPreferredActivitiesLPw(parser, userId);
+ } else if (tagName.equals("hard-preferred-activities")) {
+ readPersistentPreferredActivitiesLPw(parser, userId);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
+ parser.getName());
@@ -1024,6 +1061,20 @@
serializer.endTag(null, "preferred-activities");
}
+ void writePersistentPreferredActivitiesLPr(XmlSerializer serializer, int userId)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ serializer.startTag(null, "hard-preferred-activities");
+ PersistentPreferredIntentResolver ppir = mPersistentPreferredActivities.get(userId);
+ if (ppir != null) {
+ for (final PersistentPreferredActivity ppa : ppir.filterSet()) {
+ serializer.startTag(null, TAG_ITEM);
+ ppa.writeToXml(serializer);
+ serializer.endTag(null, TAG_ITEM);
+ }
+ }
+ serializer.endTag(null, "hard-preferred-activities");
+ }
+
void writePackageRestrictionsLPr(int userId) {
if (DEBUG_MU) {
Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1120,6 +1171,8 @@
writePreferredActivitiesLPr(serializer, userId, true);
+ writePersistentPreferredActivitiesLPr(serializer, userId);
+
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
serializer.endDocument();
@@ -1721,6 +1774,10 @@
// Upgrading from old single-user implementation;
// these are the preferred activities for user 0.
readPreferredActivitiesLPw(parser, 0);
+ } else if (tagName.equals("hard-preferred-activities")) {
+ // TODO: check whether this is okay! as it is very
+ // similar to how preferred-activities are treated
+ readPersistentPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
diff --git a/services/core/java/com/android/server/power/AutomaticBrightnessController.java b/services/core/java/com/android/server/power/AutomaticBrightnessController.java
new file mode 100644
index 0000000..3ca628a
--- /dev/null
+++ b/services/core/java/com/android/server/power/AutomaticBrightnessController.java
@@ -0,0 +1,687 @@
+/*
+ * 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.power;
+
+import com.android.server.twilight.TwilightListener;
+import com.android.server.twilight.TwilightManager;
+import com.android.server.twilight.TwilightState;
+
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.text.format.DateUtils;
+import android.util.MathUtils;
+import android.util.Spline;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+class AutomaticBrightnessController {
+ private static final String TAG = "AutomaticBrightnessController";
+
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
+
+ // If true, enables the use of the screen auto-brightness adjustment setting.
+ private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
+ PowerManager.useScreenAutoBrightnessAdjustmentFeature();
+
+ // The maximum range of gamma adjustment possible using the screen
+ // auto-brightness adjustment setting.
+ private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
+
+ // Light sensor event rate in milliseconds.
+ private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
+
+ // Period of time in which to consider light samples in milliseconds.
+ private static final int AMBIENT_LIGHT_HORIZON = 10000;
+
+ // Stability requirements in milliseconds for accepting a new brightness level. This is used
+ // for debouncing the light sensor. Different constants are used to debounce the light sensor
+ // when adapting to brighter or darker environments. This parameter controls how quickly
+ // brightness changes occur in response to an observed change in light level that exceeds the
+ // hysteresis threshold.
+ private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
+ private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
+
+ // Hysteresis constraints for brightening or darkening.
+ // The recent lux must have changed by at least this fraction relative to the
+ // current ambient lux before a change will be considered.
+ private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
+ private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
+
+ // The intercept used for the weighting calculation. This is used in order to keep all possible
+ // weighting values positive.
+ private static final int WEIGHTING_INTERCEPT = AMBIENT_LIGHT_HORIZON;
+
+ // How long the current sensor reading is assumed to be valid beyond the current time.
+ // This provides a bit of prediction, as well as ensures that the weight for the last sample is
+ // non-zero, which in turn ensures that the total weight is non-zero.
+ private static final long AMBIENT_LIGHT_PREDICTION_TIME_MILLIS = 100;
+
+ // If true, enables the use of the current time as an auto-brightness adjustment.
+ // The basic idea here is to expand the dynamic range of auto-brightness
+ // when it is especially dark outside. The light sensor tends to perform
+ // poorly at low light levels so we compensate for it by making an
+ // assumption about the environment.
+ private static final boolean USE_TWILIGHT_ADJUSTMENT =
+ PowerManager.useTwilightAdjustmentFeature();
+
+ // Specifies the maximum magnitude of the time of day adjustment.
+ private static final float TWILIGHT_ADJUSTMENT_MAX_GAMMA = 1.5f;
+
+ // The amount of time after or before sunrise over which to start adjusting
+ // the gamma. We want the change to happen gradually so that it is below the
+ // threshold of perceptibility and so that the adjustment has maximum effect
+ // well after dusk.
+ private static final long TWILIGHT_ADJUSTMENT_TIME = DateUtils.HOUR_IN_MILLIS * 2;
+
+ private static final int MSG_UPDATE_AMBIENT_LUX = 1;
+
+ // Callbacks for requesting updates to the the display's power state
+ private final Callbacks mCallbacks;
+
+ // The sensor manager.
+ private final SensorManager mSensorManager;
+
+ // The light sensor, or null if not available or needed.
+ private final Sensor mLightSensor;
+
+ // The twilight service.
+ private final TwilightManager mTwilight;
+
+ // The auto-brightness spline adjustment.
+ // The brightness values have been scaled to a range of 0..1.
+ private final Spline mScreenAutoBrightnessSpline;
+
+ // The minimum and maximum screen brightnesses.
+ private final int mScreenBrightnessRangeMinimum;
+ private final int mScreenBrightnessRangeMaximum;
+
+ // Amount of time to delay auto-brightness after screen on while waiting for
+ // the light sensor to warm-up in milliseconds.
+ // May be 0 if no warm-up is required.
+ private int mLightSensorWarmUpTimeConfig;
+
+ // Set to true if the light sensor is enabled.
+ private boolean mLightSensorEnabled;
+
+ // The time when the light sensor was enabled.
+ private long mLightSensorEnableTime;
+
+ // The currently accepted nominal ambient light level.
+ private float mAmbientLux;
+
+ // True if mAmbientLux holds a valid value.
+ private boolean mAmbientLuxValid;
+
+ // The ambient light level threshold at which to brighten or darken the screen.
+ private float mBrighteningLuxThreshold;
+ private float mDarkeningLuxThreshold;
+
+ // The most recent light sample.
+ private float mLastObservedLux;
+
+ // The time of the most light recent sample.
+ private long mLastObservedLuxTime;
+
+ // The number of light samples collected since the light sensor was enabled.
+ private int mRecentLightSamples;
+
+ // A ring buffer containing all of the recent ambient light sensor readings.
+ private AmbientLightRingBuffer mAmbientLightRingBuffer;
+
+ // The handler
+ private AutomaticBrightnessHandler mHandler;
+
+ // The screen brightness level that has been chosen by the auto-brightness
+ // algorithm. The actual brightness should ramp towards this value.
+ // We preserve this value even when we stop using the light sensor so
+ // that we can quickly revert to the previous auto-brightness level
+ // while the light sensor warms up.
+ // Use -1 if there is no current auto-brightness value available.
+ private int mScreenAutoBrightness = -1;
+
+ // The screen auto-brightness adjustment factor in the range -1 (dimmer) to 1 (brighter)
+ private float mScreenAutoBrightnessAdjustment = 0.0f;
+
+ // The last screen auto-brightness gamma. (For printing in dump() only.)
+ private float mLastScreenAutoBrightnessGamma = 1.0f;
+
+ public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
+ TwilightManager twilight, SensorManager sensorManager, Spline autoBrightnessSpline,
+ int lightSensorWarmUpTime, int brightnessMin, int brightnessMax) {
+ mCallbacks = callbacks;
+ mTwilight = twilight;
+ mSensorManager = sensorManager;
+ mScreenAutoBrightnessSpline = autoBrightnessSpline;
+ mScreenBrightnessRangeMinimum = brightnessMin;
+ mScreenBrightnessRangeMaximum = brightnessMax;
+ mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
+
+ mHandler = new AutomaticBrightnessHandler(looper);
+ mAmbientLightRingBuffer = new AmbientLightRingBuffer();
+
+ if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
+ mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ }
+
+ if (USE_TWILIGHT_ADJUSTMENT) {
+ mTwilight.registerListener(mTwilightListener, mHandler);
+ }
+ }
+
+ public int getAutomaticScreenBrightness() {
+ return mScreenAutoBrightness;
+ }
+
+ public void updatePowerState(DisplayPowerRequest request) {
+ if (setScreenAutoBrightnessAdjustment(request.screenAutoBrightnessAdjustment)
+ || setLightSensorEnabled(request.useAutoBrightness
+ && request.wantScreenOnNormal())) {
+ updateAutoBrightness(false /*sendUpdate*/);
+ }
+ }
+
+ public void dump(PrintWriter pw) {
+ pw.println();
+ pw.println("Automatic Brightness Controller Configuration:");
+ pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
+ pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
+ pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
+ pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
+
+ pw.println();
+ pw.println("Automatic Brightness Controller State:");
+ pw.println(" mLightSensor=" + mLightSensor);
+ pw.println(" mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
+ pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
+ pw.println(" mLightSensorEnableTime=" + TimeUtils.formatUptime(mLightSensorEnableTime));
+ pw.println(" mAmbientLux=" + mAmbientLux);
+ pw.println(" mBrighteningLuxThreshold=" + mBrighteningLuxThreshold);
+ pw.println(" mDarkeningLuxThreshold=" + mDarkeningLuxThreshold);
+ pw.println(" mLastObservedLux=" + mLastObservedLux);
+ pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
+ pw.println(" mRecentLightSamples=" + mRecentLightSamples);
+ pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
+ pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
+ pw.println(" mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
+ pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
+ }
+
+ private boolean setLightSensorEnabled(boolean enable) {
+ if (enable) {
+ if (!mLightSensorEnabled) {
+ mLightSensorEnabled = true;
+ mLightSensorEnableTime = SystemClock.uptimeMillis();
+ mSensorManager.registerListener(mLightSensorListener, mLightSensor,
+ LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
+ return true;
+ }
+ } else {
+ if (mLightSensorEnabled) {
+ mLightSensorEnabled = false;
+ mAmbientLuxValid = false;
+ mRecentLightSamples = 0;
+ mAmbientLightRingBuffer.clear();
+ mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
+ mSensorManager.unregisterListener(mLightSensorListener);
+ }
+ }
+ return false;
+ }
+
+ private void handleLightSensorEvent(long time, float lux) {
+ mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
+
+ applyLightSensorMeasurement(time, lux);
+ updateAmbientLux(time);
+ }
+
+ private void applyLightSensorMeasurement(long time, float lux) {
+ mRecentLightSamples++;
+ mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
+ mAmbientLightRingBuffer.push(time, lux);
+
+ // Remember this sample value.
+ mLastObservedLux = lux;
+ mLastObservedLuxTime = time;
+ }
+
+ private boolean setScreenAutoBrightnessAdjustment(float adjustment) {
+ if (adjustment != mScreenAutoBrightnessAdjustment) {
+ mScreenAutoBrightnessAdjustment = adjustment;
+ return true;
+ }
+ return false;
+ }
+
+ private void setAmbientLux(float lux) {
+ mAmbientLux = lux;
+ mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
+ mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
+ }
+
+ private float calculateAmbientLux(long now) {
+ final int N = mAmbientLightRingBuffer.size();
+ if (N == 0) {
+ Slog.e(TAG, "calculateAmbientLux: No ambient light readings available");
+ return -1;
+ }
+ float sum = 0;
+ float totalWeight = 0;
+ long endTime = AMBIENT_LIGHT_PREDICTION_TIME_MILLIS;
+ for (int i = N - 1; i >= 0; i--) {
+ long startTime = (mAmbientLightRingBuffer.getTime(i) - now);
+ float weight = calculateWeight(startTime, endTime);
+ float lux = mAmbientLightRingBuffer.getLux(i);
+ if (DEBUG) {
+ Slog.d(TAG, "calculateAmbientLux: [" +
+ (startTime) + ", " +
+ (endTime) + "]: lux=" + lux + ", weight=" + weight);
+ }
+ totalWeight += weight;
+ sum += mAmbientLightRingBuffer.getLux(i) * weight;
+ endTime = startTime;
+ }
+ if (DEBUG) {
+ Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight +
+ ", newAmbientLux=" + (sum / totalWeight));
+ }
+ return sum / totalWeight;
+ }
+
+ private static float calculateWeight(long startDelta, long endDelta) {
+ return weightIntegral(endDelta) - weightIntegral(startDelta);
+ }
+
+ // Evaluates the integral of y = x + WEIGHTING_INTERCEPT. This is always positive for the
+ // horizon we're looking at and provides a non-linear weighting for light samples.
+ private static float weightIntegral(long x) {
+ return x * (x * 0.5f + WEIGHTING_INTERCEPT);
+ }
+
+ private long nextAmbientLightBrighteningTransition(long time) {
+ final int N = mAmbientLightRingBuffer.size();
+ long earliestValidTime = time;
+ for (int i = N - 1; i >= 0; i--) {
+ if (mAmbientLightRingBuffer.getLux(i) <= mBrighteningLuxThreshold) {
+ break;
+ }
+ earliestValidTime = mAmbientLightRingBuffer.getTime(i);
+ }
+ return earliestValidTime + BRIGHTENING_LIGHT_DEBOUNCE;
+ }
+
+ private long nextAmbientLightDarkeningTransition(long time) {
+ final int N = mAmbientLightRingBuffer.size();
+ long earliestValidTime = time;
+ for (int i = N - 1; i >= 0; i--) {
+ if (mAmbientLightRingBuffer.getLux(i) >= mDarkeningLuxThreshold) {
+ break;
+ }
+ earliestValidTime = mAmbientLightRingBuffer.getTime(i);
+ }
+ return earliestValidTime + DARKENING_LIGHT_DEBOUNCE;
+ }
+
+ private void updateAmbientLux() {
+ long time = SystemClock.uptimeMillis();
+ mAmbientLightRingBuffer.prune(time - AMBIENT_LIGHT_HORIZON);
+ updateAmbientLux(time);
+ }
+
+ private void updateAmbientLux(long time) {
+ // If the light sensor was just turned on then immediately update our initial
+ // estimate of the current ambient light level.
+ if (!mAmbientLuxValid) {
+ final long timeWhenSensorWarmedUp =
+ mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
+ if (time < timeWhenSensorWarmedUp) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: "
+ + "time=" + time
+ + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp);
+ }
+ mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
+ timeWhenSensorWarmedUp);
+ return;
+ }
+ setAmbientLux(calculateAmbientLux(time));
+ mAmbientLuxValid = true;
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Initializing: "
+ + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ + ", mAmbientLux=" + mAmbientLux);
+ }
+ updateAutoBrightness(true);
+ }
+
+ long nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
+ long nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
+ float ambientLux = calculateAmbientLux(time);
+
+ if (ambientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time
+ || ambientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) {
+ setAmbientLux(ambientLux);
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: "
+ + ((ambientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
+ + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
+ + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer
+ + ", mAmbientLux=" + mAmbientLux);
+ }
+ updateAutoBrightness(true);
+ nextBrightenTransition = nextAmbientLightBrighteningTransition(time);
+ nextDarkenTransition = nextAmbientLightDarkeningTransition(time);
+ }
+ long nextTransitionTime = Math.min(nextDarkenTransition, nextBrightenTransition);
+ // If one of the transitions is ready to occur, but the total weighted ambient lux doesn't
+ // exceed the necessary threshold, then it's possible we'll get a transition time prior to
+ // now. Rather than continually checking to see whether the weighted lux exceeds the
+ // threshold, schedule an update for when we'd normally expect another light sample, which
+ // should be enough time to decide whether we should actually transition to the new
+ // weighted ambient lux or not.
+ nextTransitionTime =
+ nextTransitionTime > time ? nextTransitionTime : time + LIGHT_SENSOR_RATE_MILLIS;
+ if (DEBUG) {
+ Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for "
+ + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
+ }
+ mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
+ }
+
+ private void updateAutoBrightness(boolean sendUpdate) {
+ if (!mAmbientLuxValid) {
+ return;
+ }
+
+ float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
+ float gamma = 1.0f;
+
+ if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
+ && mScreenAutoBrightnessAdjustment != 0.0f) {
+ final float adjGamma = MathUtils.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
+ Math.min(1.0f, Math.max(-1.0f, -mScreenAutoBrightnessAdjustment)));
+ gamma *= adjGamma;
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
+ }
+ }
+
+ if (USE_TWILIGHT_ADJUSTMENT) {
+ TwilightState state = mTwilight.getCurrentState();
+ if (state != null && state.isNight()) {
+ final long now = System.currentTimeMillis();
+ final float earlyGamma =
+ getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
+ final float lateGamma =
+ getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
+ gamma *= earlyGamma * lateGamma;
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
+ + ", lateGamma=" + lateGamma);
+ }
+ }
+ }
+
+ if (gamma != 1.0f) {
+ final float in = value;
+ value = MathUtils.pow(value, gamma);
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
+ + ", in=" + in + ", out=" + value);
+ }
+ }
+
+ int newScreenAutoBrightness =
+ clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
+ if (mScreenAutoBrightness != newScreenAutoBrightness) {
+ if (DEBUG) {
+ Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
+ + mScreenAutoBrightness + ", newScreenAutoBrightness="
+ + newScreenAutoBrightness);
+ }
+
+ mScreenAutoBrightness = newScreenAutoBrightness;
+ mLastScreenAutoBrightnessGamma = gamma;
+ if (sendUpdate) {
+ mCallbacks.updateBrightness();
+ }
+ }
+ }
+
+ private int clampScreenBrightness(int value) {
+ return MathUtils.constrain(value,
+ mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
+ }
+
+ private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
+ if (lastSunset < 0 || nextSunrise < 0
+ || now < lastSunset || now > nextSunrise) {
+ return 1.0f;
+ }
+
+ if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
+ return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
+ (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
+ return MathUtils.lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
+ (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
+ }
+
+ return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
+ }
+
+ private final class AutomaticBrightnessHandler extends Handler {
+ public AutomaticBrightnessHandler(Looper looper) {
+ super(looper, null, true /*async*/);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_AMBIENT_LUX:
+ updateAmbientLux();
+ break;
+ }
+ }
+ }
+
+ private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (mLightSensorEnabled) {
+ final long time = SystemClock.uptimeMillis();
+ final float lux = event.values[0];
+ handleLightSensorEvent(time, lux);
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Not used.
+ }
+ };
+
+ private final TwilightListener mTwilightListener = new TwilightListener() {
+ @Override
+ public void onTwilightStateChanged() {
+ updateAutoBrightness(true /*sendUpdate*/);
+ }
+ };
+
+ /** Callbacks to request updates to the display's power state. */
+ interface Callbacks {
+ void updateBrightness();
+ }
+
+ private static final class AmbientLightRingBuffer{
+ // Proportional extra capacity of the buffer beyond the expected number of light samples
+ // in the horizon
+ private static final float BUFFER_SLACK = 1.5f;
+ private static final int DEFAULT_CAPACITY =
+ (int) Math.ceil(AMBIENT_LIGHT_HORIZON * BUFFER_SLACK / LIGHT_SENSOR_RATE_MILLIS);
+ private float[] mRingLux;
+ private long[] mRingTime;
+ private int mCapacity;
+
+ // The first valid element and the next open slot.
+ // Note that if mCount is zero then there are no valid elements.
+ private int mStart;
+ private int mEnd;
+ private int mCount;
+
+ public AmbientLightRingBuffer() {
+ this(DEFAULT_CAPACITY);
+ }
+
+ public AmbientLightRingBuffer(int initialCapacity) {
+ mCapacity = initialCapacity;
+ mRingLux = new float[mCapacity];
+ mRingTime = new long[mCapacity];
+ }
+
+ public float getLux(int index) {
+ return mRingLux[offsetOf(index)];
+ }
+
+ public long getTime(int index) {
+ return mRingTime[offsetOf(index)];
+ }
+
+ public void push(long time, float lux) {
+ int next = mEnd;
+ if (mCount == mCapacity) {
+ int newSize = mCapacity * 2;
+
+ float[] newRingLux = new float[newSize];
+ long[] newRingTime = new long[newSize];
+ int length = mCapacity - mStart;
+ System.arraycopy(mRingLux, mStart, newRingLux, 0, length);
+ System.arraycopy(mRingTime, mStart, newRingTime, 0, length);
+ if (mStart != 0) {
+ System.arraycopy(mRingLux, 0, newRingLux, length, mStart);
+ System.arraycopy(mRingTime, 0, newRingTime, length, mStart);
+ }
+ mRingLux = newRingLux;
+ mRingTime = newRingTime;
+
+ next = mCapacity;
+ mCapacity = newSize;
+ mStart = 0;
+ }
+ mRingTime[next] = time;
+ mRingLux[next] = lux;
+ mEnd = next + 1;
+ if (mEnd == mCapacity) {
+ mEnd = 0;
+ }
+ mCount++;
+ }
+
+ public void prune(long horizon) {
+ if (mCount == 0) {
+ return;
+ }
+
+ while (mCount > 1) {
+ int next = mStart + 1;
+ if (next >= mCapacity) {
+ next -= mCapacity;
+ }
+ if (mRingTime[next] > horizon) {
+ // Some light sensors only produce data upon a change in the ambient light
+ // levels, so we need to consider the previous measurement as the ambient light
+ // level for all points in time up until we receive a new measurement. Thus, we
+ // always want to keep the youngest element that would be removed from the
+ // buffer and just set its measurement time to the horizon time since at that
+ // point it is the ambient light level, and to remove it would be to drop a
+ // valid data point within our horizon.
+ break;
+ }
+ mStart = next;
+ mCount -= 1;
+ }
+
+ if (mRingTime[mStart] < horizon) {
+ mRingTime[mStart] = horizon;
+ }
+ }
+
+ public int size() {
+ return mCount;
+ }
+
+ public boolean isEmpty() {
+ return mCount == 0;
+ }
+
+ public void clear() {
+ mStart = 0;
+ mEnd = 0;
+ mCount = 0;
+ }
+
+ @Override
+ public String toString() {
+ final int length = mCapacity - mStart;
+ float[] lux = new float[mCount];
+ long[] time = new long[mCount];
+
+ if (mCount <= length) {
+ System.arraycopy(mRingLux, mStart, lux, 0, mCount);
+ System.arraycopy(mRingTime, mStart, time, 0, mCount);
+ } else {
+ System.arraycopy(mRingLux, mStart, lux, 0, length);
+ System.arraycopy(mRingLux, 0, lux, length, mCount - length);
+
+ System.arraycopy(mRingTime, mStart, time, 0, length);
+ System.arraycopy(mRingTime, 0, time, length, mCount - length);
+ }
+ return "AmbientLightRingBuffer{mCapacity=" + mCapacity
+ + ", mStart=" + mStart
+ + ", mEnd=" + mEnd
+ + ", mCount=" + mCount
+ + ", mRingLux=" + Arrays.toString(lux)
+ + ", mRingTime=" + Arrays.toString(time)
+ + "}";
+ }
+
+ private int offsetOf(int index) {
+ if (index >= mCount || index < 0) {
+ throw new ArrayIndexOutOfBoundsException(index);
+ }
+ index += mStart;
+ if (index >= mCapacity) {
+ index -= mCapacity;
+ }
+ return index;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/power/DisplayPowerController.java b/services/core/java/com/android/server/power/DisplayPowerController.java
index b63f625..12d51aa 100644
--- a/services/core/java/com/android/server/power/DisplayPowerController.java
+++ b/services/core/java/com/android/server/power/DisplayPowerController.java
@@ -35,7 +35,7 @@
import android.os.PowerManager;
import android.os.SystemClock;
import android.text.format.DateUtils;
-import android.util.FloatMath;
+import android.util.MathUtils;
import android.util.Slog;
import android.util.Spline;
import android.util.TimeUtils;
@@ -64,12 +64,11 @@
* For debugging, you can make the electron beam and brightness animations run
* slower by changing the "animator duration scale" option in Development Settings.
*/
-final class DisplayPowerController {
+final class DisplayPowerController implements AutomaticBrightnessController.Callbacks {
private static final String TAG = "DisplayPowerController";
private static boolean DEBUG = false;
private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
- private static final boolean DEBUG_PRETEND_LIGHT_SENSOR_ABSENT = false;
// If true, uses the electron beam on animation.
// We might want to turn this off if we cannot get a guarantee that the screen
@@ -77,13 +76,6 @@
// screen state returns. Playing the animation can also be somewhat slow.
private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
- // If true, enables the use of the screen auto-brightness adjustment setting.
- private static final boolean USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT =
- PowerManager.useScreenAutoBrightnessAdjustmentFeature();
-
- // The maximum range of gamma adjustment possible using the screen
- // auto-brightness adjustment setting.
- private static final float SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA = 3.0f;
// The minimum reduction in brightness when dimmed.
private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
@@ -110,7 +102,6 @@
private static final int MSG_UPDATE_POWER_STATE = 1;
private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
- private static final int MSG_LIGHT_SENSOR_DEBOUNCED = 3;
private static final int PROXIMITY_UNKNOWN = -1;
private static final int PROXIMITY_NEGATIVE = 0;
@@ -123,41 +114,10 @@
// Trigger proximity if distance is less than 5 cm.
private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
- // Light sensor event rate in milliseconds.
- private static final int LIGHT_SENSOR_RATE_MILLIS = 1000;
-
- // A rate for generating synthetic light sensor events in the case where the light
- // sensor hasn't reported any new data in a while and we need it to update the
- // debounce filter. We only synthesize light sensor measurements when needed.
- private static final int SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS =
- LIGHT_SENSOR_RATE_MILLIS * 2;
-
// Brightness animation ramp rate in brightness units per second.
private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
- // IIR filter time constants in milliseconds for computing two moving averages of
- // the light samples. One is a long-term average and the other is a short-term average.
- // We can use these filters to assess trends in ambient brightness.
- // The short term average gives us a filtered but relatively low latency measurement.
- // The long term average informs us about the overall trend.
- private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
- private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 5000;
-
- // Stability requirements in milliseconds for accepting a new brightness
- // level. This is used for debouncing the light sensor. Different constants
- // are used to debounce the light sensor when adapting to brighter or darker environments.
- // This parameter controls how quickly brightness changes occur in response to
- // an observed change in light level that exceeds the hysteresis threshold.
- private static final long BRIGHTENING_LIGHT_DEBOUNCE = 4000;
- private static final long DARKENING_LIGHT_DEBOUNCE = 8000;
-
- // Hysteresis constraints for brightening or darkening.
- // The recent lux must have changed by at least this fraction relative to the
- // current ambient lux before a change will be considered.
- private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
- private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
-
private final Object mLock = new Object();
// Notifier for sending asynchronous notifications.
@@ -181,17 +141,14 @@
// The lights service.
private final LightsManager mLights;
- // The twilight service.
- private final TwilightManager mTwilight;
-
// The sensor manager.
private final SensorManager mSensorManager;
// The proximity sensor, or null if not available or needed.
private Sensor mProximitySensor;
- // The light sensor, or null if not available or needed.
- private Sensor mLightSensor;
+ // The doze screen brightness.
+ private final int mScreenBrightnessDozeConfig;
// The dim screen brightness.
private final int mScreenBrightnessDimConfig;
@@ -205,15 +162,6 @@
// True if auto-brightness should be used.
private boolean mUseSoftwareAutoBrightnessConfig;
- // The auto-brightness spline adjustment.
- // The brightness values have been scaled to a range of 0..1.
- private Spline mScreenAutoBrightnessSpline;
-
- // Amount of time to delay auto-brightness after screen on while waiting for
- // the light sensor to warm-up in milliseconds.
- // May be 0 if no warm-up is required.
- private int mLightSensorWarmUpTimeConfig;
-
// True if we should fade the screen while turning it off, false if we should play
// a stylish electron beam animation instead.
private boolean mElectronBeamFadesConfig;
@@ -283,67 +231,18 @@
// The elapsed real time when the screen on was blocked.
private long mScreenOnBlockStartRealTime;
- // Set to true if the light sensor is enabled.
- private boolean mLightSensorEnabled;
-
- // The time when the light sensor was enabled.
- private long mLightSensorEnableTime;
-
- // The currently accepted nominal ambient light level.
- private float mAmbientLux;
-
- // True if mAmbientLux holds a valid value.
- private boolean mAmbientLuxValid;
-
- // The ambient light level threshold at which to brighten or darken the screen.
- private float mBrighteningLuxThreshold;
- private float mDarkeningLuxThreshold;
-
- // The most recent light sample.
- private float mLastObservedLux;
-
- // The time of the most light recent sample.
- private long mLastObservedLuxTime;
-
- // The number of light samples collected since the light sensor was enabled.
- private int mRecentLightSamples;
-
- // The long-term and short-term filtered light measurements.
- private float mRecentShortTermAverageLux;
- private float mRecentLongTermAverageLux;
-
- // The direction in which the average lux is moving relative to the current ambient lux.
- // 0 if not changing or within hysteresis threshold.
- // 1 if brightening beyond hysteresis threshold.
- // -1 if darkening beyond hysteresis threshold.
- private int mDebounceLuxDirection;
-
- // The time when the average lux last changed direction.
- private long mDebounceLuxTime;
-
- // The screen brightness level that has been chosen by the auto-brightness
- // algorithm. The actual brightness should ramp towards this value.
- // We preserve this value even when we stop using the light sensor so
- // that we can quickly revert to the previous auto-brightness level
- // while the light sensor warms up.
- // Use -1 if there is no current auto-brightness value available.
- private int mScreenAutoBrightness = -1;
-
- // The last screen auto-brightness gamma. (For printing in dump() only.)
- private float mLastScreenAutoBrightnessGamma = 1.0f;
-
// True if the screen auto-brightness value is actually being used to
// set the display brightness.
private boolean mUsingScreenAutoBrightness;
+ // The controller for the automatic brightness level.
+ private AutomaticBrightnessController mAutomaticBrightnessController;
+
// Animators.
private ObjectAnimator mElectronBeamOnAnimator;
private ObjectAnimator mElectronBeamOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
- // Twilight changed. We might recalculate auto-brightness values.
- private boolean mTwilightChanged;
-
/**
* Creates the display power controller.
*/
@@ -359,17 +258,21 @@
mCallbackHandler = callbackHandler;
mLights = lights;
- mTwilight = twilight;
mSensorManager = sensorManager;
final Resources resources = context.getResources();
+ mScreenBrightnessDozeConfig = clampAbsoluteBrightness(resources.getInteger(
+ com.android.internal.R.integer.config_screenBrightnessDoze));
+
mScreenBrightnessDimConfig = clampAbsoluteBrightness(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessDim));
- int screenBrightnessMinimum = Math.min(resources.getInteger(
+ int screenBrightnessRangeMinimum = clampAbsoluteBrightness(Math.min(resources.getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum),
- mScreenBrightnessDimConfig);
+ mScreenBrightnessDimConfig));
+
+ mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
mUseSoftwareAutoBrightnessConfig = resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
@@ -378,9 +281,11 @@
com.android.internal.R.array.config_autoBrightnessLevels);
int[] screenBrightness = resources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
+ int lightSensorWarmUpTimeConfig = resources.getInteger(
+ com.android.internal.R.integer.config_lightSensorWarmupTime);
- mScreenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
- if (mScreenAutoBrightnessSpline == null) {
+ Spline screenAutoBrightnessSpline = createAutoBrightnessSpline(lux, screenBrightness);
+ if (screenAutoBrightnessSpline == null) {
Slog.e(TAG, "Error in config.xml. config_autoBrightnessLcdBacklightValues "
+ "(size " + screenBrightness.length + ") "
+ "must be monotic and have exactly one more entry than "
@@ -389,17 +294,17 @@
+ "Auto-brightness will be disabled.");
mUseSoftwareAutoBrightnessConfig = false;
} else {
- if (screenBrightness[0] < screenBrightnessMinimum) {
- screenBrightnessMinimum = screenBrightness[0];
+ if (screenBrightness[0] < screenBrightnessRangeMinimum) {
+ screenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightness[0]);
}
+ mAutomaticBrightnessController = new AutomaticBrightnessController(this, looper,
+ twilight, sensorManager, screenAutoBrightnessSpline,
+ lightSensorWarmUpTimeConfig, screenBrightnessRangeMinimum,
+ mScreenBrightnessRangeMaximum);
}
-
- mLightSensorWarmUpTimeConfig = resources.getInteger(
- com.android.internal.R.integer.config_lightSensorWarmupTime);
}
- mScreenBrightnessRangeMinimum = clampAbsoluteBrightness(screenBrightnessMinimum);
- mScreenBrightnessRangeMaximum = PowerManager.BRIGHTNESS_ON;
+ mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
mElectronBeamFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
@@ -412,39 +317,6 @@
}
}
- if (mUseSoftwareAutoBrightnessConfig
- && !DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
- mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
- }
-
- if (mUseSoftwareAutoBrightnessConfig && USE_TWILIGHT_ADJUSTMENT) {
- mTwilight.registerListener(mTwilightListener, mHandler);
- }
- }
-
- private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
- try {
- final int n = brightness.length;
- float[] x = new float[n];
- float[] y = new float[n];
- y[0] = normalizeAbsoluteBrightness(brightness[0]);
- for (int i = 1; i < n; i++) {
- x[i] = lux[i - 1];
- y[i] = normalizeAbsoluteBrightness(brightness[i]);
- }
-
- Spline spline = Spline.createMonotoneCubicSpline(x, y);
- if (DEBUG) {
- Slog.d(TAG, "Auto-brightness spline: " + spline);
- for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
- Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
- }
- }
- return spline;
- } catch (IllegalArgumentException ex) {
- Slog.e(TAG, "Could not create auto-brightness spline.", ex);
- return null;
- }
}
/**
@@ -566,9 +438,7 @@
// Update the power state request.
final boolean mustNotify;
boolean mustInitialize = false;
- boolean updateAutoBrightness = mTwilightChanged;
- boolean wasDim = false;
- mTwilightChanged = false;
+ boolean wasDimOrDoze = false;
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
@@ -583,11 +453,8 @@
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
- if (mPowerRequest.screenAutoBrightnessAdjustment
- != mPendingRequestLocked.screenAutoBrightnessAdjustment) {
- updateAutoBrightness = true;
- }
- wasDim = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM);
+ wasDimOrDoze = (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM
+ || mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE);
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
@@ -633,18 +500,19 @@
}
// Turn on the light sensor if needed.
- if (mLightSensor != null) {
- setLightSensorEnabled(mPowerRequest.useAutoBrightness
- && wantScreenOn(mPowerRequest.screenState), updateAutoBrightness);
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.updatePowerState(mPowerRequest);
}
// Set the screen brightness.
- if (wantScreenOn(mPowerRequest.screenState)) {
+ if (mPowerRequest.wantScreenOnAny()) {
int target;
boolean slow;
- if (mScreenAutoBrightness >= 0 && mLightSensorEnabled) {
+ int screenAutoBrightness = mAutomaticBrightnessController != null ?
+ mAutomaticBrightnessController.getAutomaticScreenBrightness() : -1;
+ if (screenAutoBrightness >= 0 && mPowerRequest.useAutoBrightness) {
// Use current auto-brightness value.
- target = mScreenAutoBrightness;
+ target = screenAutoBrightness;
slow = mUsingScreenAutoBrightness;
mUsingScreenAutoBrightness = true;
} else {
@@ -656,12 +524,16 @@
slow = false;
mUsingScreenAutoBrightness = false;
}
- if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
+ if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DOZE) {
+ // Dim quickly to the doze state.
+ target = mScreenBrightnessDozeConfig;
+ slow = false;
+ } else if (mPowerRequest.screenState == DisplayPowerRequest.SCREEN_STATE_DIM) {
// Dim quickly by at least some minimum amount.
target = Math.min(target - SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig);
slow = false;
- } else if (wasDim) {
+ } else if (wasDimOrDoze) {
// Brighten quickly.
slow = false;
}
@@ -674,7 +546,7 @@
// Animate the screen on or off.
if (!mScreenOffBecauseOfProximity) {
- if (wantScreenOn(mPowerRequest.screenState)) {
+ if (mPowerRequest.wantScreenOnAny()) {
// Want screen on.
// Wait for previous off animation to complete beforehand.
// It is relatively short but if we cancel it and switch to the
@@ -751,6 +623,11 @@
}
}
+ @Override
+ public void updateBrightness() {
+ sendUpdatePowerState();
+ }
+
private void blockScreenOn() {
if (!mScreenOnWasBlocked) {
mScreenOnWasBlocked = true;
@@ -783,25 +660,8 @@
}
private int clampScreenBrightness(int value) {
- return clamp(value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
- }
-
- private static int clampAbsoluteBrightness(int value) {
- return clamp(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
- }
-
- private static int clamp(int value, int min, int max) {
- if (value <= min) {
- return min;
- }
- if (value >= max) {
- return max;
- }
- return value;
- }
-
- private static float normalizeAbsoluteBrightness(int value) {
- return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
+ return MathUtils.constrain(
+ value, mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
}
private void animateScreenBrightness(int target, int rate) {
@@ -902,270 +762,6 @@
mPendingProximityDebounceTime = debounceTime;
}
- private void setLightSensorEnabled(boolean enable, boolean updateAutoBrightness) {
- if (enable) {
- if (!mLightSensorEnabled) {
- updateAutoBrightness = true;
- mLightSensorEnabled = true;
- mLightSensorEnableTime = SystemClock.uptimeMillis();
- mSensorManager.registerListener(mLightSensorListener, mLightSensor,
- LIGHT_SENSOR_RATE_MILLIS * 1000, mHandler);
- }
- } else {
- if (mLightSensorEnabled) {
- mLightSensorEnabled = false;
- mAmbientLuxValid = false;
- mRecentLightSamples = 0;
- mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
- mSensorManager.unregisterListener(mLightSensorListener);
- }
- }
- if (updateAutoBrightness) {
- updateAutoBrightness(false);
- }
- }
-
- private void handleLightSensorEvent(long time, float lux) {
- mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
-
- applyLightSensorMeasurement(time, lux);
- updateAmbientLux(time);
- }
-
- private void applyLightSensorMeasurement(long time, float lux) {
- // Update our filters.
- mRecentLightSamples += 1;
- if (mRecentLightSamples == 1) {
- mRecentShortTermAverageLux = lux;
- mRecentLongTermAverageLux = lux;
- } else {
- final long timeDelta = time - mLastObservedLuxTime;
- mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
- * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
- mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
- * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
- }
-
- // Remember this sample value.
- mLastObservedLux = lux;
- mLastObservedLuxTime = time;
- }
-
- private void setAmbientLux(float lux) {
- mAmbientLux = lux;
- mBrighteningLuxThreshold = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
- mDarkeningLuxThreshold = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
- }
-
- private void updateAmbientLux(long time) {
- // If the light sensor was just turned on then immediately update our initial
- // estimate of the current ambient light level.
- if (!mAmbientLuxValid) {
- final long timeWhenSensorWarmedUp =
- mLightSensorWarmUpTimeConfig + mLightSensorEnableTime;
- if (time < timeWhenSensorWarmedUp) {
- mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
- timeWhenSensorWarmedUp);
- return;
- }
- setAmbientLux(mRecentShortTermAverageLux);
- mAmbientLuxValid = true;
- mDebounceLuxDirection = 0;
- mDebounceLuxTime = time;
- if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Initializing: "
- + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
- + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
- + ", mAmbientLux=" + mAmbientLux);
- }
- updateAutoBrightness(true);
- } else if (mRecentShortTermAverageLux > mBrighteningLuxThreshold
- && mRecentLongTermAverageLux > mBrighteningLuxThreshold) {
- // The ambient environment appears to be brightening.
- if (mDebounceLuxDirection <= 0) {
- mDebounceLuxDirection = 1;
- mDebounceLuxTime = time;
- if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Possibly brightened, waiting for "
- + BRIGHTENING_LIGHT_DEBOUNCE + " ms: "
- + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
- + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
- + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
- + ", mAmbientLux=" + mAmbientLux);
- }
- }
- long debounceTime = mDebounceLuxTime + BRIGHTENING_LIGHT_DEBOUNCE;
- if (time < debounceTime) {
- mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
- return;
- }
- setAmbientLux(mRecentShortTermAverageLux);
- if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Brightened: "
- + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
- + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
- + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
- + ", mAmbientLux=" + mAmbientLux);
- }
- updateAutoBrightness(true);
- } else if (mRecentShortTermAverageLux < mDarkeningLuxThreshold
- && mRecentLongTermAverageLux < mDarkeningLuxThreshold) {
- // The ambient environment appears to be darkening.
- if (mDebounceLuxDirection >= 0) {
- mDebounceLuxDirection = -1;
- mDebounceLuxTime = time;
- if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Possibly darkened, waiting for "
- + DARKENING_LIGHT_DEBOUNCE + " ms: "
- + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
- + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
- + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
- + ", mAmbientLux=" + mAmbientLux);
- }
- }
- long debounceTime = mDebounceLuxTime + DARKENING_LIGHT_DEBOUNCE;
- if (time < debounceTime) {
- mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
- return;
- }
- // Be conservative about reducing the brightness, only reduce it a little bit
- // at a time to avoid having to bump it up again soon.
- setAmbientLux(Math.max(mRecentShortTermAverageLux, mRecentLongTermAverageLux));
- if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Darkened: "
- + "mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
- + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
- + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
- + ", mAmbientLux=" + mAmbientLux);
- }
- updateAutoBrightness(true);
- } else if (mDebounceLuxDirection != 0) {
- // No change or change is within the hysteresis thresholds.
- mDebounceLuxDirection = 0;
- mDebounceLuxTime = time;
- if (DEBUG) {
- Slog.d(TAG, "updateAmbientLux: Canceled debounce: "
- + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold
- + ", mDarkeningLuxThreshold=" + mDarkeningLuxThreshold
- + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
- + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux
- + ", mAmbientLux=" + mAmbientLux);
- }
- }
-
- // Now that we've done all of that, we haven't yet posted a debounce
- // message. So consider the case where current lux is beyond the
- // threshold. It's possible that the light sensor may not report values
- // if the light level does not change, so we need to occasionally
- // synthesize sensor readings in order to make sure the brightness is
- // adjusted accordingly. Note these thresholds may have changed since
- // we entered the function because we called setAmbientLux and
- // updateAutoBrightness along the way.
- if (mLastObservedLux > mBrighteningLuxThreshold
- || mLastObservedLux < mDarkeningLuxThreshold) {
- mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED,
- time + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS);
- }
- }
-
- private void debounceLightSensor() {
- if (mLightSensorEnabled) {
- long time = SystemClock.uptimeMillis();
- if (time >= mLastObservedLuxTime + SYNTHETIC_LIGHT_SENSOR_RATE_MILLIS) {
- if (DEBUG) {
- Slog.d(TAG, "debounceLightSensor: Synthesizing light sensor measurement "
- + "after " + (time - mLastObservedLuxTime) + " ms.");
- }
- applyLightSensorMeasurement(time, mLastObservedLux);
- }
- updateAmbientLux(time);
- }
- }
-
- private void updateAutoBrightness(boolean sendUpdate) {
- if (!mAmbientLuxValid) {
- return;
- }
-
- float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
- float gamma = 1.0f;
-
- if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
- && mPowerRequest.screenAutoBrightnessAdjustment != 0.0f) {
- final float adjGamma = FloatMath.pow(SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT_MAX_GAMMA,
- Math.min(1.0f, Math.max(-1.0f,
- -mPowerRequest.screenAutoBrightnessAdjustment)));
- gamma *= adjGamma;
- if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: adjGamma=" + adjGamma);
- }
- }
-
- if (USE_TWILIGHT_ADJUSTMENT) {
- TwilightState state = mTwilight.getCurrentState();
- if (state != null && state.isNight()) {
- final long now = System.currentTimeMillis();
- final float earlyGamma =
- getTwilightGamma(now, state.getYesterdaySunset(), state.getTodaySunrise());
- final float lateGamma =
- getTwilightGamma(now, state.getTodaySunset(), state.getTomorrowSunrise());
- gamma *= earlyGamma * lateGamma;
- if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: earlyGamma=" + earlyGamma
- + ", lateGamma=" + lateGamma);
- }
- }
- }
-
- if (gamma != 1.0f) {
- final float in = value;
- value = FloatMath.pow(value, gamma);
- if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma
- + ", in=" + in + ", out=" + value);
- }
- }
-
- int newScreenAutoBrightness = clampScreenBrightness(
- Math.round(value * PowerManager.BRIGHTNESS_ON));
- if (mScreenAutoBrightness != newScreenAutoBrightness) {
- if (DEBUG) {
- Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
- + mScreenAutoBrightness + ", newScreenAutoBrightness="
- + newScreenAutoBrightness);
- }
-
- mScreenAutoBrightness = newScreenAutoBrightness;
- mLastScreenAutoBrightnessGamma = gamma;
- if (sendUpdate) {
- sendUpdatePowerState();
- }
- }
- }
-
- private static float getTwilightGamma(long now, long lastSunset, long nextSunrise) {
- if (lastSunset < 0 || nextSunrise < 0
- || now < lastSunset || now > nextSunrise) {
- return 1.0f;
- }
-
- if (now < lastSunset + TWILIGHT_ADJUSTMENT_TIME) {
- return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
- (float)(now - lastSunset) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- if (now > nextSunrise - TWILIGHT_ADJUSTMENT_TIME) {
- return lerp(1.0f, TWILIGHT_ADJUSTMENT_MAX_GAMMA,
- (float)(nextSunrise - now) / TWILIGHT_ADJUSTMENT_TIME);
- }
-
- return TWILIGHT_ADJUSTMENT_MAX_GAMMA;
- }
-
- private static float lerp(float x, float y, float alpha) {
- return x + (y - x) * alpha;
- }
-
private void sendOnStateChangedWithWakelock() {
mDisplaySuspendBlocker.acquire();
mCallbackHandler.post(mOnStateChangedRunnable);
@@ -1219,13 +815,12 @@
pw.println();
pw.println("Display Controller Configuration:");
+ pw.println(" mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
pw.println(" mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
pw.println(" mScreenBrightnessRangeMinimum=" + mScreenBrightnessRangeMinimum);
pw.println(" mScreenBrightnessRangeMaximum=" + mScreenBrightnessRangeMaximum);
pw.println(" mUseSoftwareAutoBrightnessConfig="
+ mUseSoftwareAutoBrightnessConfig);
- pw.println(" mScreenAutoBrightnessSpline=" + mScreenAutoBrightnessSpline);
- pw.println(" mLightSensorWarmUpTimeConfig=" + mLightSensorWarmUpTimeConfig);
mHandler.runWithScissors(new Runnable() {
@Override
@@ -1249,25 +844,7 @@
pw.println(" mPendingProximityDebounceTime="
+ TimeUtils.formatUptime(mPendingProximityDebounceTime));
pw.println(" mScreenOffBecauseOfProximity=" + mScreenOffBecauseOfProximity);
-
- pw.println(" mLightSensor=" + mLightSensor);
- pw.println(" mLightSensorEnabled=" + mLightSensorEnabled);
- pw.println(" mLightSensorEnableTime="
- + TimeUtils.formatUptime(mLightSensorEnableTime));
- pw.println(" mAmbientLux=" + mAmbientLux);
- pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
- pw.println(" mLastObservedLux=" + mLastObservedLux);
- pw.println(" mLastObservedLuxTime="
- + TimeUtils.formatUptime(mLastObservedLuxTime));
- pw.println(" mRecentLightSamples=" + mRecentLightSamples);
- pw.println(" mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
- pw.println(" mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
- pw.println(" mDebounceLuxDirection=" + mDebounceLuxDirection);
- pw.println(" mDebounceLuxTime=" + TimeUtils.formatUptime(mDebounceLuxTime));
- pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
- pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
- pw.println(" mTwilight.getCurrentState()=" + mTwilight.getCurrentState());
if (mElectronBeamOnAnimator != null) {
pw.println(" mElectronBeamOnAnimator.isStarted()=" +
@@ -1281,6 +858,11 @@
if (mPowerState != null) {
mPowerState.dump(pw);
}
+
+ if (mAutomaticBrightnessController != null) {
+ mAutomaticBrightnessController.dump(pw);
+ }
+
}
private static String proximityToString(int state) {
@@ -1296,13 +878,37 @@
}
}
- private static boolean wantScreenOn(int state) {
- switch (state) {
- case DisplayPowerRequest.SCREEN_STATE_BRIGHT:
- case DisplayPowerRequest.SCREEN_STATE_DIM:
- return true;
+ private static Spline createAutoBrightnessSpline(int[] lux, int[] brightness) {
+ try {
+ final int n = brightness.length;
+ float[] x = new float[n];
+ float[] y = new float[n];
+ y[0] = normalizeAbsoluteBrightness(brightness[0]);
+ for (int i = 1; i < n; i++) {
+ x[i] = lux[i - 1];
+ y[i] = normalizeAbsoluteBrightness(brightness[i]);
+ }
+
+ Spline spline = Spline.createMonotoneCubicSpline(x, y);
+ if (DEBUG) {
+ Slog.d(TAG, "Auto-brightness spline: " + spline);
+ for (float v = 1f; v < lux[lux.length - 1] * 1.25f; v *= 1.25f) {
+ Slog.d(TAG, String.format(" %7.1f: %7.1f", v, spline.interpolate(v)));
+ }
+ }
+ return spline;
+ } catch (IllegalArgumentException ex) {
+ Slog.e(TAG, "Could not create auto-brightness spline.", ex);
+ return null;
}
- return false;
+ }
+
+ private static float normalizeAbsoluteBrightness(int value) {
+ return (float)clampAbsoluteBrightness(value) / PowerManager.BRIGHTNESS_ON;
+ }
+
+ private static int clampAbsoluteBrightness(int value) {
+ return MathUtils.constrain(value, PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON);
}
/**
@@ -1329,10 +935,6 @@
case MSG_PROXIMITY_SENSOR_DEBOUNCED:
debounceProximitySensor();
break;
-
- case MSG_LIGHT_SENSOR_DEBOUNCED:
- debounceLightSensor();
- break;
}
}
}
@@ -1353,28 +955,4 @@
// Not used.
}
};
-
- private final SensorEventListener mLightSensorListener = new SensorEventListener() {
- @Override
- public void onSensorChanged(SensorEvent event) {
- if (mLightSensorEnabled) {
- final long time = SystemClock.uptimeMillis();
- final float lux = event.values[0];
- handleLightSensorEvent(time, lux);
- }
- }
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {
- // Not used.
- }
- };
-
- private final TwilightListener mTwilightListener = new TwilightListener() {
- @Override
- public void onTwilightStateChanged() {
- mTwilightChanged = true;
- updatePowerState();
- }
- };
}
diff --git a/services/core/java/com/android/server/power/DisplayPowerRequest.java b/services/core/java/com/android/server/power/DisplayPowerRequest.java
index 22f17d7..c5e46cb 100644
--- a/services/core/java/com/android/server/power/DisplayPowerRequest.java
+++ b/services/core/java/com/android/server/power/DisplayPowerRequest.java
@@ -30,10 +30,11 @@
*/
final class DisplayPowerRequest {
public static final int SCREEN_STATE_OFF = 0;
- public static final int SCREEN_STATE_DIM = 1;
- public static final int SCREEN_STATE_BRIGHT = 2;
+ public static final int SCREEN_STATE_DOZE = 1;
+ public static final int SCREEN_STATE_DIM = 2;
+ public static final int SCREEN_STATE_BRIGHT = 3;
- // The requested minimum screen power state: off, dim or bright.
+ // The requested minimum screen power state: off, doze, dim or bright.
public int screenState;
// If true, the proximity sensor overrides the screen state when an object is
@@ -75,6 +76,23 @@
copyFrom(other);
}
+ // Returns true if we want the screen on in any mode, including doze.
+ public boolean wantScreenOnAny() {
+ return screenState != SCREEN_STATE_OFF;
+ }
+
+ // Returns true if we want the screen on in a normal mode, excluding doze.
+ // This is usually what we want to tell the rest of the system. For compatibility
+ // reasons, we pretend the screen is off when dozing.
+ public boolean wantScreenOnNormal() {
+ return screenState == SCREEN_STATE_DIM || screenState == SCREEN_STATE_BRIGHT;
+ }
+
+ public boolean wantLightSensorEnabled() {
+ // Specifically, we don't want the light sensor while dozing.
+ return useAutoBrightness && wantScreenOnNormal();
+ }
+
public void copyFrom(DisplayPowerRequest other) {
screenState = other.screenState;
useProximitySensor = other.useProximitySensor;
@@ -114,4 +132,13 @@
+ ", useAutoBrightness=" + useAutoBrightness
+ ", blockScreenOn=" + blockScreenOn;
}
+
+ public static boolean wantScreenOn(int state) {
+ switch(state) {
+ case SCREEN_STATE_DIM:
+ case SCREEN_STATE_BRIGHT:
+ return true;
+ }
+ return false;
+ }
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b2344e6..f420988 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -20,12 +20,12 @@
import com.android.internal.app.IBatteryStats;
import com.android.server.BatteryService;
import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
import com.android.server.twilight.TwilightManager;
import com.android.server.Watchdog;
-import com.android.server.dreams.DreamManagerService;
import android.Manifest;
import android.content.BroadcastReceiver;
@@ -57,6 +57,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
@@ -82,7 +83,7 @@
// Message: Sent when a user activity timeout occurs to update the power state.
private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
- // Message: Sent when the device enters or exits a napping or dreaming state.
+ // Message: Sent when the device enters or exits a dreaming or dozing state.
private static final int MSG_SANDMAN = 2;
// Message: Sent when the screen on blocker is released.
private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
@@ -116,19 +117,21 @@
// Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
// The screen should be off or in the process of being turned off by the display controller.
+ // The device typically passes through the dozing state first.
private static final int WAKEFULNESS_ASLEEP = 0;
// Wakefulness: The device is fully awake. It can be put to sleep by a call to goToSleep().
- // When the user activity timeout expires, the device may start napping or go to sleep.
+ // When the user activity timeout expires, the device may start dreaming or go to sleep.
private static final int WAKEFULNESS_AWAKE = 1;
- // Wakefulness: The device is napping. It is deciding whether to dream or go to sleep
- // but hasn't gotten around to it yet. It can be awoken by a call to wakeUp(), which
- // ends the nap. User activity may brighten the screen but does not end the nap.
- private static final int WAKEFULNESS_NAPPING = 2;
// Wakefulness: The device is dreaming. It can be awoken by a call to wakeUp(),
// which ends the dream. The device goes to sleep when goToSleep() is called, when
// the dream ends or when unplugged.
// User activity may brighten the screen but does not end the dream.
- private static final int WAKEFULNESS_DREAMING = 3;
+ private static final int WAKEFULNESS_DREAMING = 2;
+ // Wakefulness: The device is dozing. It is almost asleep but is allowing a special
+ // low-power "doze" dream to run which keeps the display on but lets the application
+ // processor be suspended. It can be awoken by a call to wakeUp() which ends the dream.
+ // The device fully goes to sleep if the dream cannot be started or ends on its own.
+ private static final int WAKEFULNESS_DOZING = 3;
// Summarizes the state of all active wakelocks.
private static final int WAKE_LOCK_CPU = 1 << 0;
@@ -137,6 +140,7 @@
private static final int WAKE_LOCK_BUTTON_BRIGHT = 1 << 3;
private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
+ private static final int WAKE_LOCK_DOZE = 1 << 6;
// Summarizes the user activity state.
private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -163,11 +167,6 @@
// Poll interval in milliseconds for watching boot animation finished.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
- // If the battery level drops by this percentage and the user activity timeout
- // has expired, then assume the device is receiving insufficient current to charge
- // effectively and terminate the dream.
- private static final int DREAM_BATTERY_LEVEL_DRAIN_CUTOFF = 5;
-
private final Context mContext;
private LightsManager mLightsManager;
private BatteryService mBatteryService;
@@ -181,7 +180,7 @@
private DisplayPowerController mDisplayPowerController;
private WirelessChargerDetector mWirelessChargerDetector;
private SettingsObserver mSettingsObserver;
- private DreamManagerService mDreamManager;
+ private DreamManagerInternal mDreamManager;
private Light mAttentionLight;
private final Object mLock = new Object();
@@ -194,6 +193,10 @@
// This is distinct from the screen power state, which is managed separately.
private int mWakefulness;
+ // True if the sandman has just been summoned for the first time since entering the
+ // dreaming or dozing state. Indicates whether a new dream should begin.
+ private boolean mSandmanSummoned;
+
// True if MSG_SANDMAN has been scheduled.
private boolean mSandmanScheduled;
@@ -264,6 +267,14 @@
// True if boot completed occurred. We keep the screen on until this happens.
private boolean mBootCompleted;
+ // True if auto-suspend mode is enabled.
+ // Refer to autosuspend.h.
+ private boolean mAutoSuspendModeEnabled;
+
+ // True if interactive mode is enabled.
+ // Refer to power.h.
+ private boolean mInteractiveModeEnabled;
+
// True if the device is plugged into a power source.
private boolean mIsPowered;
@@ -281,6 +292,12 @@
// The current dock state.
private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ // True to decouple auto-suspend mode from the display state.
+ private boolean mDecoupleAutoSuspendModeFromDisplayConfig;
+
+ // True to decouple interactive mode from the display state.
+ private boolean mDecoupleInteractiveModeFromDisplayConfig;
+
// True if the device should wake up when plugged or unplugged.
private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
@@ -299,6 +316,22 @@
// Default value for dreams activate-on-dock
private boolean mDreamsActivatedOnDockByDefaultConfig;
+ // True if dreams can run while not plugged in.
+ private boolean mDreamsEnabledOnBatteryConfig;
+
+ // Minimum battery level to allow dreaming when powered.
+ // Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelMinimumWhenPoweredConfig;
+
+ // Minimum battery level to allow dreaming when not powered.
+ // Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelMinimumWhenNotPoweredConfig;
+
+ // If the battery level drops by this percentage and the user activity timeout
+ // has expired, then assume the device is receiving insufficient current to charge
+ // effectively and terminate the dream. Use -1 to disable this safety feature.
+ private int mDreamsBatteryLevelDrainCutoffConfig;
+
// True if dreams are enabled by the user.
private boolean mDreamsEnabledSetting;
@@ -433,10 +466,10 @@
}
}
- public void systemReady(TwilightManager twilight, DreamManagerService dreamManager) {
+ public void systemReady() {
synchronized (mLock) {
mSystemReady = true;
- mDreamManager = dreamManager;
+ mDreamManager = LocalServices.getService(DreamManagerInternal.class);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
@@ -454,7 +487,8 @@
// The display power controller runs on the power manager service's
// own handler thread to ensure timely operation.
mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
- mContext, mNotifier, mLightsManager, twilight, sensorManager,
+ mContext, mNotifier, mLightsManager,
+ LocalServices.getService(TwilightManager.class), sensorManager,
mDisplaySuspendBlocker, mDisplayBlanker,
mDisplayPowerControllerCallbacks, mHandler);
@@ -521,6 +555,10 @@
private void readConfigurationLocked() {
final Resources resources = mContext.getResources();
+ mDecoupleAutoSuspendModeFromDisplayConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleAutoSuspendModeFromDisplay);
+ mDecoupleInteractiveModeFromDisplayConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay);
mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
com.android.internal.R.bool.config_unplugTurnsOnScreen);
mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean(
@@ -533,6 +571,14 @@
com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
+ mDreamsEnabledOnBatteryConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_dreamsEnabledOnBattery);
+ mDreamsBatteryLevelMinimumWhenPoweredConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenPowered);
+ mDreamsBatteryLevelMinimumWhenNotPoweredConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelMinimumWhenNotPowered);
+ mDreamsBatteryLevelDrainCutoffConfig = resources.getInteger(
+ com.android.internal.R.integer.config_dreamsBatteryLevelDrainCutoff);
}
private void updateSettingsLocked() {
@@ -760,6 +806,7 @@
case PowerManager.SCREEN_DIM_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.DOZE_WAKE_LOCK:
return true;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
@@ -792,7 +839,8 @@
}
if (eventTime < mLastSleepTime || eventTime < mLastWakeTime
- || mWakefulness == WAKEFULNESS_ASLEEP || !mBootCompleted || !mSystemReady) {
+ || mWakefulness == WAKEFULNESS_ASLEEP || mWakefulness == WAKEFULNESS_DOZING
+ || !mBootCompleted || !mSystemReady) {
return false;
}
@@ -841,18 +889,21 @@
switch (mWakefulness) {
case WAKEFULNESS_ASLEEP:
Slog.i(TAG, "Waking up from sleep...");
- sendPendingNotificationsLocked();
- mNotifier.onWakeUpStarted();
- mSendWakeUpFinishedNotificationWhenReady = true;
break;
case WAKEFULNESS_DREAMING:
Slog.i(TAG, "Waking up from dream...");
break;
- case WAKEFULNESS_NAPPING:
- Slog.i(TAG, "Waking up from nap...");
+ case WAKEFULNESS_DOZING:
+ Slog.i(TAG, "Waking up from dozing...");
break;
}
+ if (mWakefulness != WAKEFULNESS_DREAMING) {
+ sendPendingNotificationsLocked();
+ mNotifier.onWakeUpStarted();
+ mSendWakeUpFinishedNotificationWhenReady = true;
+ }
+
mLastWakeTime = eventTime;
mWakefulness = WAKEFULNESS_AWAKE;
mDirty |= DIRTY_WAKEFULNESS;
@@ -875,13 +926,17 @@
}
}
+ // This method is called goToSleep for historical reasons but we actually start
+ // dozing before really going to sleep.
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason) {
if (DEBUG_SPEW) {
Slog.d(TAG, "goToSleepNoUpdateLocked: eventTime=" + eventTime + ", reason=" + reason);
}
- if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ if (eventTime < mLastWakeTime
+ || mWakefulness == WAKEFULNESS_ASLEEP
+ || mWakefulness == WAKEFULNESS_DOZING
|| !mBootCompleted || !mSystemReady) {
return false;
}
@@ -905,7 +960,8 @@
mLastSleepTime = eventTime;
mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_ASLEEP;
+ mWakefulness = WAKEFULNESS_DOZING;
+ mSandmanSummoned = true;
// Report the number of wake locks that will be cleared by going to sleep.
int numWakeLocksCleared = 0;
@@ -945,7 +1001,26 @@
Slog.i(TAG, "Nap time...");
mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_NAPPING;
+ mWakefulness = WAKEFULNESS_DREAMING;
+ mSandmanSummoned = true;
+ return true;
+ }
+
+ // Done dozing, drop everything and go to sleep.
+ private boolean reallyGoToSleepNoUpdateLocked(long eventTime) {
+ if (DEBUG_SPEW) {
+ Slog.d(TAG, "reallyGoToSleepNoUpdateLocked: eventTime=" + eventTime);
+ }
+
+ if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ || !mBootCompleted || !mSystemReady) {
+ return false;
+ }
+
+ Slog.i(TAG, "Sleeping...");
+
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_ASLEEP;
return true;
}
@@ -1021,7 +1096,7 @@
mPlugType = mBatteryService.getPlugType();
mBatteryLevel = mBatteryService.getBatteryLevel();
- if (DEBUG) {
+ if (DEBUG_SPEW) {
Slog.d(TAG, "updateIsPoweredLocked: wasPowered=" + wasPowered
+ ", mIsPowered=" + mIsPowered
+ ", oldPlugType=" + oldPlugType
@@ -1081,8 +1156,7 @@
}
// If already dreaming and becoming powered, then don't wake.
- if (mIsPowered && (mWakefulness == WAKEFULNESS_NAPPING
- || mWakefulness == WAKEFULNESS_DREAMING)) {
+ if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
return false;
}
@@ -1129,35 +1203,45 @@
mWakeLockSummary |= WAKE_LOCK_CPU;
break;
case PowerManager.FULL_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU
| WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_BUTTON_BRIGHT;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_BRIGHT;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.SCREEN_DIM_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
mWakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_SCREEN_DIM;
- if (mWakefulness == WAKEFULNESS_AWAKE) {
- mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
- }
+ }
+ if (mWakefulness == WAKEFULNESS_AWAKE) {
+ mWakeLockSummary |= WAKE_LOCK_STAY_AWAKE;
}
break;
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING
+ || mWakefulness == WAKEFULNESS_DOZING) {
mWakeLockSummary |= WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
break;
+ case PowerManager.DOZE_WAKE_LOCK:
+ if (mWakefulness == WAKEFULNESS_DOZING) {
+ mWakeLockSummary |= WAKE_LOCK_DOZE;
+ }
+ break;
}
}
@@ -1182,7 +1266,8 @@
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
- if (mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (mWakefulness == WAKEFULNESS_AWAKE
+ || mWakefulness == WAKEFULNESS_DREAMING) {
final int screenOffTimeout = getScreenOffTimeoutLocked();
final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
@@ -1203,8 +1288,7 @@
&& mLastUserActivityTimeNoChangeLights >= mLastWakeTime) {
nextTimeout = mLastUserActivityTimeNoChangeLights + screenOffTimeout;
if (now < nextTimeout
- && mDisplayPowerRequest.screenState
- != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ && mDisplayPowerRequest.wantScreenOnNormal()) {
mUserActivitySummary = mDisplayPowerRequest.screenState
== DisplayPowerRequest.SCREEN_STATE_BRIGHT ?
USER_ACTIVITY_SCREEN_BRIGHT : USER_ACTIVITY_SCREEN_DIM;
@@ -1266,7 +1350,7 @@
/**
* Updates the wakefulness of the device.
*
- * This is the function that decides whether the device should start napping
+ * This is the function that decides whether the device should start dreaming
* based on the current wake locks and user activity state. It may modify mDirty
* if the wakefulness changes.
*
@@ -1355,7 +1439,7 @@
}
/**
- * Called when the device enters or exits a napping or dreaming state.
+ * Called when the device enters or exits a dreaming or dozing state.
*
* We do this asynchronously because we must call out of the power manager to start
* the dream and we don't want to hold our lock while doing so. There is a risk that
@@ -1363,46 +1447,60 @@
*/
private void handleSandman() { // runs on handler thread
// Handle preconditions.
- boolean startDreaming = false;
+ final boolean startDreaming;
+ final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
- boolean canDream = canDreamLocked();
- if (DEBUG_SPEW) {
- Slog.d(TAG, "handleSandman: canDream=" + canDream
- + ", mWakefulness=" + wakefulnessToString(mWakefulness));
- }
-
- if (canDream && mWakefulness == WAKEFULNESS_NAPPING) {
- startDreaming = true;
+ wakefulness = mWakefulness;
+ if (mSandmanSummoned) {
+ startDreaming = ((wakefulness == WAKEFULNESS_DREAMING && canDreamLocked())
+ || wakefulness == WAKEFULNESS_DOZING);
+ mSandmanSummoned = false;
+ } else {
+ startDreaming = false;
}
}
// Start dreaming if needed.
// We only control the dream on the handler thread, so we don't need to worry about
// concurrent attempts to start or stop the dream.
- boolean isDreaming = false;
+ final boolean isDreaming;
if (mDreamManager != null) {
+ // Restart the dream whenever the sandman is summoned.
if (startDreaming) {
- mDreamManager.startDream();
+ mDreamManager.stopDream();
+ mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
}
isDreaming = mDreamManager.isDreaming();
+ } else {
+ isDreaming = false;
}
// Update dream state.
- // We might need to stop the dream again if the preconditions changed.
- boolean continueDreaming = false;
synchronized (mLock) {
- if (isDreaming && canDreamLocked()) {
- if (mWakefulness == WAKEFULNESS_NAPPING) {
- mWakefulness = WAKEFULNESS_DREAMING;
- mDirty |= DIRTY_WAKEFULNESS;
- mBatteryLevelWhenDreamStarted = mBatteryLevel;
- updatePowerStateLocked();
- continueDreaming = true;
- } else if (mWakefulness == WAKEFULNESS_DREAMING) {
- if (!isBeingKeptAwakeLocked()
+ // Remember the initial battery level when the dream started.
+ if (startDreaming && isDreaming) {
+ mBatteryLevelWhenDreamStarted = mBatteryLevel;
+ if (wakefulness == WAKEFULNESS_DOZING) {
+ Slog.i(TAG, "Dozing...");
+ } else {
+ Slog.i(TAG, "Dreaming...");
+ }
+ }
+
+ // If preconditions changed, wait for the next iteration to determine
+ // whether the dream should continue (or be restarted).
+ if (mSandmanSummoned || mWakefulness != wakefulness) {
+ return; // wait for next cycle
+ }
+
+ // Determine whether the dream should continue.
+ if (wakefulness == WAKEFULNESS_DREAMING) {
+ if (isDreaming && canDreamLocked()) {
+ if (mDreamsBatteryLevelDrainCutoffConfig >= 0
&& mBatteryLevel < mBatteryLevelWhenDreamStarted
- - DREAM_BATTERY_LEVEL_DRAIN_CUTOFF) {
+ - mDreamsBatteryLevelDrainCutoffConfig
+ && !isBeingKeptAwakeLocked()) {
// If the user activity timeout expired and the battery appears
// to be draining faster than it is charging then stop dreaming
// and go to sleep.
@@ -1412,53 +1510,64 @@
+ mBatteryLevelWhenDreamStarted + "%. "
+ "Battery level now: " + mBatteryLevel + "%.");
} else {
- continueDreaming = true;
+ return; // continue dreaming
}
}
- }
- if (!continueDreaming) {
- handleDreamFinishedLocked();
+
+ // Dream has ended or will be stopped. Update the power state.
+ if (isItBedTimeYetLocked()) {
+ goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
+ PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ updatePowerStateLocked();
+ } else {
+ wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
+ updatePowerStateLocked();
+ }
+ } else if (wakefulness == WAKEFULNESS_DOZING) {
+ if (isDreaming) {
+ return; // continue dozing
+ }
+
+ // Doze has ended or will be stopped. Update the power state.
+ reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis());
+ updatePowerStateLocked();
}
}
- // Stop dreaming if needed.
- // It's possible that something else changed to make us need to start the dream again.
- // If so, then the power manager will have posted another message to the handler
- // to take care of it later.
- if (mDreamManager != null) {
- if (!continueDreaming) {
- mDreamManager.stopDream();
- }
+ // Stop dream.
+ if (isDreaming) {
+ mDreamManager.stopDream();
}
}
/**
- * Returns true if the device is allowed to dream in its current state
- * assuming that it is currently napping or dreaming.
+ * Returns true if the device is allowed to dream in its current state.
+ * This function is not called when dozing.
*/
private boolean canDreamLocked() {
- return mDreamsSupportedConfig
- && mDreamsEnabledSetting
- && mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF
- && mBootCompleted
- && (mIsPowered || isBeingKeptAwakeLocked());
- }
-
- /**
- * Called when a dream is ending to figure out what to do next.
- */
- private void handleDreamFinishedLocked() {
- if (mWakefulness == WAKEFULNESS_NAPPING
- || mWakefulness == WAKEFULNESS_DREAMING) {
- if (isItBedTimeYetLocked()) {
- goToSleepNoUpdateLocked(SystemClock.uptimeMillis(),
- PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
- updatePowerStateLocked();
- } else {
- wakeUpNoUpdateLocked(SystemClock.uptimeMillis());
- updatePowerStateLocked();
+ if (mWakefulness != WAKEFULNESS_DREAMING
+ || !mDreamsSupportedConfig
+ || !mDreamsEnabledSetting
+ || !mDisplayPowerRequest.wantScreenOnNormal()
+ || !mBootCompleted) {
+ return false;
+ }
+ if (!isBeingKeptAwakeLocked()) {
+ if (!mIsPowered && !mDreamsEnabledOnBatteryConfig) {
+ return false;
+ }
+ if (!mIsPowered
+ && mDreamsBatteryLevelMinimumWhenNotPoweredConfig >= 0
+ && mBatteryLevel < mDreamsBatteryLevelMinimumWhenNotPoweredConfig) {
+ return false;
+ }
+ if (mIsPowered
+ && mDreamsBatteryLevelMinimumWhenPoweredConfig >= 0
+ && mBatteryLevel < mDreamsBatteryLevelMinimumWhenPoweredConfig) {
+ return false;
}
}
+ return true;
}
private void handleScreenOnBlockerReleased() {
@@ -1480,11 +1589,11 @@
if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
| DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
| DIRTY_SETTINGS | DIRTY_SCREEN_ON_BLOCKER_RELEASED)) != 0) {
- int newScreenState = getDesiredScreenPowerStateLocked();
+ final int newScreenState = getDesiredScreenPowerStateLocked();
if (newScreenState != mDisplayPowerRequest.screenState) {
mDisplayPowerRequest.screenState = newScreenState;
nativeSetPowerState(
- newScreenState != DisplayPowerRequest.SCREEN_STATE_OFF,
+ mDisplayPowerRequest.wantScreenOnNormal(),
newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT);
}
@@ -1553,6 +1662,10 @@
return DisplayPowerRequest.SCREEN_STATE_OFF;
}
+ if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
+ return DisplayPowerRequest.SCREEN_STATE_DOZE;
+ }
+
if ((mWakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
|| (mUserActivitySummary & USER_ACTIVITY_SCREEN_BRIGHT) != 0
|| !mBootCompleted) {
@@ -1604,7 +1717,18 @@
*/
private void updateSuspendBlockerLocked() {
final boolean needWakeLockSuspendBlocker = ((mWakeLockSummary & WAKE_LOCK_CPU) != 0);
- final boolean needDisplaySuspendBlocker = needDisplaySuspendBlocker();
+ final boolean needDisplaySuspendBlocker = needDisplaySuspendBlockerLocked();
+ final boolean autoSuspend = !needDisplaySuspendBlocker;
+
+ // Disable auto-suspend if needed.
+ if (!autoSuspend) {
+ if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(false);
+ }
+ if (mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(true);
+ }
+ }
// First acquire suspend blockers if needed.
if (needWakeLockSuspendBlocker && !mHoldingWakeLockSuspendBlocker) {
@@ -1625,17 +1749,27 @@
mDisplaySuspendBlocker.release();
mHoldingDisplaySuspendBlocker = false;
}
+
+ // Enable auto-suspend if needed.
+ if (autoSuspend) {
+ if (mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(false);
+ }
+ if (mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(true);
+ }
+ }
}
/**
* Return true if we must keep a suspend blocker active on behalf of the display.
* We do so if the screen is on or is in transition between states.
*/
- private boolean needDisplaySuspendBlocker() {
+ private boolean needDisplaySuspendBlockerLocked() {
if (!mDisplayReady) {
return true;
}
- if (mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF) {
+ if (mDisplayPowerRequest.wantScreenOnNormal()) {
// If we asked for the screen to be on but it is off due to the proximity
// sensor then we may suspend but only if the configuration allows it.
// On some hardware it may not be safe to suspend because the proximity
@@ -1645,13 +1779,34 @@
return true;
}
}
+ // Let the system suspend if the screen is off or dozing.
return false;
}
+ private void setAutoSuspendModeLocked(boolean enable) {
+ if (enable != mAutoSuspendModeEnabled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting auto-suspend mode to " + enable);
+ }
+ mAutoSuspendModeEnabled = enable;
+ nativeSetAutoSuspend(enable);
+ }
+ }
+
+ private void setInteractiveModeLocked(boolean enable) {
+ if (enable != mInteractiveModeEnabled) {
+ if (DEBUG) {
+ Slog.d(TAG, "Setting interactive mode to " + enable);
+ }
+ mInteractiveModeEnabled = enable;
+ nativeSetInteractive(enable);
+ }
+ }
+
private boolean isScreenOnInternal() {
synchronized (mLock) {
return !mSystemReady
- || mDisplayPowerRequest.screenState != DisplayPowerRequest.SCREEN_STATE_OFF;
+ || mDisplayPowerRequest.wantScreenOnNormal();
}
}
@@ -1885,10 +2040,13 @@
pw.println(" mProximityPositive=" + mProximityPositive);
pw.println(" mBootCompleted=" + mBootCompleted);
pw.println(" mSystemReady=" + mSystemReady);
+ pw.println(" mAutoSuspendModeEnabled=" + mAutoSuspendModeEnabled);
+ pw.println(" mInteactiveModeEnabled=" + mInteractiveModeEnabled);
pw.println(" mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
pw.println(" mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary));
pw.println(" mRequestWaitForNegativeProximity=" + mRequestWaitForNegativeProximity);
pw.println(" mSandmanScheduled=" + mSandmanScheduled);
+ pw.println(" mSandmanSummoned=" + mSandmanSummoned);
pw.println(" mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
pw.println(" mLastSleepTime=" + TimeUtils.formatUptime(mLastSleepTime));
pw.println(" mSendWakeUpFinishedNotificationWhenReady="
@@ -1904,6 +2062,10 @@
pw.println();
pw.println("Settings and Configuration:");
+ pw.println(" mDecoupleAutoSuspendModeFromDisplayConfig="
+ + mDecoupleAutoSuspendModeFromDisplayConfig);
+ pw.println(" mDecoupleInteractiveModeFromDisplayConfig="
+ + mDecoupleInteractiveModeFromDisplayConfig);
pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig="
+ mWakeUpWhenPluggedOrUnpluggedConfig);
pw.println(" mSuspendWhenScreenOffDueToProximityConfig="
@@ -1914,6 +2076,14 @@
+ mDreamsActivatedOnSleepByDefaultConfig);
pw.println(" mDreamsActivatedOnDockByDefaultConfig="
+ mDreamsActivatedOnDockByDefaultConfig);
+ pw.println(" mDreamsEnabledOnBatteryConfig="
+ + mDreamsEnabledOnBatteryConfig);
+ pw.println(" mDreamsBatteryLevelMinimumWhenPoweredConfig="
+ + mDreamsBatteryLevelMinimumWhenPoweredConfig);
+ pw.println(" mDreamsBatteryLevelMinimumWhenNotPoweredConfig="
+ + mDreamsBatteryLevelMinimumWhenNotPoweredConfig);
+ pw.println(" mDreamsBatteryLevelDrainCutoffConfig="
+ + mDreamsBatteryLevelDrainCutoffConfig);
pw.println(" mDreamsEnabledSetting=" + mDreamsEnabledSetting);
pw.println(" mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
pw.println(" mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
@@ -1989,8 +2159,8 @@
return "Awake";
case WAKEFULNESS_DREAMING:
return "Dreaming";
- case WAKEFULNESS_NAPPING:
- return "Napping";
+ case WAKEFULNESS_DOZING:
+ return "Dozing";
default:
return Integer.toString(wakefulness);
}
@@ -2167,6 +2337,7 @@
+ " (uid=" + mOwnerUid + ", pid=" + mOwnerPid + ", ws=" + mWorkSource + ")";
}
+ @SuppressWarnings("deprecation")
private String getLockLevelString() {
switch (mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
@@ -2179,6 +2350,8 @@
return "PARTIAL_WAKE_LOCK ";
case PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK:
return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
+ case PowerManager.DOZE_WAKE_LOCK:
+ return "DOZE_WAKE_LOCK ";
default:
return "??? ";
}
@@ -2309,16 +2482,24 @@
synchronized (this) {
mBlanked = true;
mDisplayManagerInternal.blankAllDisplaysFromPowerManager();
- nativeSetInteractive(false);
- nativeSetAutoSuspend(true);
+ if (!mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(false);
+ }
+ if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(true);
+ }
}
}
@Override
public void unblankAllDisplays() {
synchronized (this) {
- nativeSetAutoSuspend(false);
- nativeSetInteractive(true);
+ if (!mDecoupleAutoSuspendModeFromDisplayConfig) {
+ setAutoSuspendModeLocked(false);
+ }
+ if (!mDecoupleInteractiveModeFromDisplayConfig) {
+ setInteractiveModeLocked(true);
+ }
mDisplayManagerInternal.unblankAllDisplaysFromPowerManager();
mBlanked = false;
}
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 43a99e0..260e97a 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -454,6 +454,7 @@
notification.tickerText = title;
notification.flags |= Notification.FLAG_NO_CLEAR;
notification.setLatestEventInfo(context, title, details, intent);
+ notification.visibility = Notification.VISIBILITY_PUBLIC;
mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 3cccf1d..7fe895b 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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.wm;
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 574ae2d..c09ea5c 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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.wm;
@@ -125,8 +139,54 @@
}
}
+ /**
+ * @param layer The new layer value.
+ * @param inTransaction Whether the call is made within a surface transaction.
+ */
+ void adjustSurface(int layer, boolean inTransaction) {
+ final int dw, dh;
+ final float xPos, yPos;
+ if (!mStack.isFullscreen()) {
+ dw = mBounds.width();
+ dh = mBounds.height();
+ xPos = mBounds.left;
+ yPos = mBounds.top;
+ } else {
+ // Set surface size to screen size.
+ final DisplayInfo info = mDisplayContent.getDisplayInfo();
+ // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose
+ // a corner.
+ dw = (int) (info.logicalWidth * 1.5);
+ dh = (int) (info.logicalHeight * 1.5);
+ // back off position so 1/4 of Surface is before and 1/4 is after.
+ xPos = -1 * dw / 6;
+ yPos = -1 * dh / 6;
+ }
+
+ try {
+ if (!inTransaction) {
+ SurfaceControl.openTransaction();
+ }
+ mDimSurface.setPosition(xPos, yPos);
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.setLayer(layer);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting size or layer", e);
+ } finally {
+ if (!inTransaction) {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ mLastBounds.set(mBounds);
+ mLayer = layer;
+ }
+
+ // Assumes that surface transactions are currently closed.
void setBounds(Rect bounds) {
mBounds.set(bounds);
+ if (isDimming() && !mLastBounds.equals(bounds)) {
+ adjustSurface(mLayer, false);
+ }
}
/**
@@ -164,35 +224,8 @@
return;
}
- final int dw, dh;
- final float xPos, yPos;
- if (!mStack.isFullscreen()) {
- dw = mBounds.width();
- dh = mBounds.height();
- xPos = mBounds.left;
- yPos = mBounds.top;
- } else {
- // Set surface size to screen size.
- final DisplayInfo info = mDisplayContent.getDisplayInfo();
- // Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
- // corner.
- dw = (int) (info.logicalWidth * 1.5);
- dh = (int) (info.logicalHeight * 1.5);
- // back off position so 1/4 of Surface is before and 1/4 is after.
- xPos = -1 * dw / 6;
- yPos = -1 * dh / 6;
- }
-
if (!mLastBounds.equals(mBounds) || mLayer != layer) {
- try {
- mDimSurface.setPosition(xPos, yPos);
- mDimSurface.setSize(dw, dh);
- mDimSurface.setLayer(layer);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Failure setting size or layer", e);
- }
- mLastBounds.set(mBounds);
- mLayer = layer;
+ adjustSurface(layer, true);
}
long curTime = SystemClock.uptimeMillis();
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 415a06b..68834d8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -170,22 +170,13 @@
}
void updateDisplayInfo() {
- // Save old size.
- int oldWidth = mDisplayInfo.logicalWidth;
- int oldHeight = mDisplayInfo.logicalHeight;
mDisplay.getDisplayInfo(mDisplayInfo);
-
for (int i = mStacks.size() - 1; i >= 0; --i) {
- final TaskStack stack = mStacks.get(i);
- if (!stack.isFullscreen()) {
- stack.resizeBounds(oldWidth, oldHeight, mDisplayInfo.logicalWidth,
- mDisplayInfo.logicalHeight);
- }
+ mStacks.get(i).updateDisplayInfo();
}
}
void getLogicalDisplayRect(Rect out) {
- updateDisplayInfo();
// Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
final int orientation = mDisplayInfo.rotation;
boolean rotated = (orientation == Surface.ROTATION_90
@@ -291,11 +282,12 @@
}
boolean isDimming() {
- boolean result = false;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
- result |= mStacks.get(stackNdx).isDimming();
+ if (mStacks.get(stackNdx).isDimming()) {
+ return true;
+ }
}
- return result;
+ return false;
}
void stopDimmingIfNeeded() {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 803b9ac..4aae5c1 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -364,8 +364,8 @@
* motion event processing when the screen is off since these events are normally
* dropped. */
@Override
- public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) {
- return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(policyFlags);
+ public int interceptMotionBeforeQueueingWhenScreenOff(long whenNanos, int policyFlags) {
+ return mService.mPolicy.interceptMotionBeforeQueueingWhenScreenOff(whenNanos, policyFlags);
}
/* Provides an opportunity for the window manager policy to process a key before
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c301ffe..09c4e20 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,10 +16,12 @@
package com.android.server.wm;
+import static com.android.server.wm.WindowManagerService.TAG;
+
import android.util.EventLog;
+import android.util.Slog;
class Task {
-// private final String TAG = "TaskGroup";
TaskStack mStack;
final AppTokenList mAppTokens = new AppTokenList();
final int taskId;
@@ -38,17 +40,24 @@
}
void addAppToken(int addPos, AppWindowToken wtoken) {
+ final int lastPos = mAppTokens.size();
+ if (addPos > lastPos) {
+ // We lost an app token. Don't crash though.
+ Slog.e(TAG, "Task.addAppToken: Out of bounds attempt token=" + wtoken + " addPos="
+ + addPos + " lastPos=" + lastPos);
+ addPos = lastPos;
+ }
mAppTokens.add(addPos, wtoken);
+ mDeferRemoval = false;
}
boolean removeAppToken(AppWindowToken wtoken) {
- mAppTokens.remove(wtoken);
+ boolean removed = mAppTokens.remove(wtoken);
if (mAppTokens.size() == 0) {
EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, taskId,
"removeAppToken: last token");
- return true;
}
- return false;
+ return removed;
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7d8cff4..c70bc62 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -47,12 +47,17 @@
* mTaskHistory in the ActivityStack with the same mStackId */
private final ArrayList<Task> mTasks = new ArrayList<Task>();
- /** Content limits relative to the DisplayContent this sits in. Empty indicates fullscreen,
- * Nonempty is size of this TaskStack but is also used to scale if DisplayContent changes. */
- Rect mBounds = new Rect();
+ /** For comparison with DisplayContent bounds. */
+ private Rect mTmpRect = new Rect();
+
+ /** Content limits relative to the DisplayContent this sits in. */
+ private Rect mBounds = new Rect();
+
+ /** Whether mBounds is fullscreen */
+ private boolean mFullscreen = true;
/** Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND} */
- DimLayer mDimLayer;
+ private DimLayer mDimLayer;
/** The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer. */
WindowStateAnimator mDimWinAnimator;
@@ -86,7 +91,7 @@
return mTasks;
}
- private void resizeWindows() {
+ void resizeWindows() {
final boolean underStatusBar = mBounds.top == 0;
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
@@ -108,7 +113,13 @@
}
boolean setBounds(Rect bounds) {
- if (mBounds.equals(bounds)) {
+ boolean oldFullscreen = mFullscreen;
+ if (mDisplayContent != null) {
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ mFullscreen = mTmpRect.equals(bounds);
+ }
+
+ if (mBounds.equals(bounds) && oldFullscreen == mFullscreen) {
return false;
}
@@ -116,25 +127,22 @@
mAnimationBackgroundSurface.setBounds(bounds);
mBounds.set(bounds);
- resizeWindows();
return true;
}
void getBounds(Rect out) {
- if (mDisplayContent != null) {
- if (mBounds.isEmpty()) {
- mDisplayContent.getLogicalDisplayRect(out);
- } else {
- out.set(mBounds);
- }
- out.intersect(mDisplayContent.mContentRect);
- } else {
- out.set(mBounds);
+ out.set(mBounds);
+ }
+
+ void updateDisplayInfo() {
+ if (mFullscreen && mDisplayContent != null) {
+ mDisplayContent.getLogicalDisplayRect(mTmpRect);
+ setBounds(mTmpRect);
}
}
boolean isFullscreen() {
- return mBounds.isEmpty();
+ return mFullscreen;
}
boolean isAnimating() {
@@ -152,19 +160,6 @@
return false;
}
- void resizeBounds(float oldWidth, float oldHeight, float newWidth, float newHeight) {
- if (oldWidth == newWidth && oldHeight == newHeight) {
- return;
- }
- float widthScale = newWidth / oldWidth;
- float heightScale = newHeight / oldHeight;
- mBounds.left = (int)(mBounds.left * widthScale + 0.5);
- mBounds.top = (int)(mBounds.top * heightScale + 0.5);
- mBounds.right = (int)(mBounds.right * widthScale + 0.5);
- mBounds.bottom = (int)(mBounds.bottom * heightScale + 0.5);
- resizeWindows();
- }
-
/**
* Put a Task in this stack. Used for adding and moving.
* @param task The task to add.
@@ -233,6 +228,7 @@
mDisplayContent = displayContent;
mDimLayer = new DimLayer(mService, this, displayContent);
mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+ updateDisplayInfo();
}
void detachDisplay() {
@@ -371,11 +367,11 @@
(mDisplayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0 &&
!isAnimating()) {
mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_DETACH;
- mService.detachStack(mStackId);
if ((mDisplayContent.mDeferredActions & DisplayContent.DEFER_REMOVAL) != 0) {
mDisplayContent.mDeferredActions &= ~DisplayContent.DEFER_REMOVAL;
mService.onDisplayRemoved(mDisplayContent.getDisplayId());
}
+ mService.detachStack(mStackId);
}
for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task task = mTasks.get(taskNdx);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index a9947c0..0c68258 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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.wm;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8f07e27..f03f9a2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3486,7 +3486,7 @@
Task task = mTaskIdToTask.get(taskId);
if (task == null) {
- task = createTask(taskId, stackId, userId, atoken);
+ createTask(taskId, stackId, userId, atoken);
} else {
task.addAppToken(addPos, atoken);
}
@@ -3839,27 +3839,23 @@
}
synchronized(mWindowMap) {
- boolean changed = false;
+ final AppWindowToken newFocus;
if (token == null) {
if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
- changed = mFocusedApp != null;
- mFocusedApp = null;
- if (changed) {
- mInputMonitor.setFocusedAppLw(null);
- }
+ newFocus = null;
} else {
- AppWindowToken newFocus = findAppWindowToken(token);
+ newFocus = findAppWindowToken(token);
if (newFocus == null) {
Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token);
- return;
}
- changed = mFocusedApp != newFocus;
if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus
+ " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow);
+ }
+
+ final boolean changed = mFocusedApp != newFocus;
+ if (changed) {
mFocusedApp = newFocus;
- if (changed) {
- mInputMonitor.setFocusedAppLw(newFocus);
- }
+ mInputMonitor.setFocusedAppLw(null);
}
if (moveFocusNow && changed) {
@@ -4208,10 +4204,25 @@
AppWindowToken atoken = findAppWindowToken(token);
if (atoken != null) {
atoken.appFullscreen = toOpaque;
+ // When making translucent, wait until windows below have been drawn.
+ if (toOpaque) {
+ // Making opaque so do it now.
+ setWindowOpaque(token, true);
+ }
requestTraversal();
}
}
+ public void setWindowOpaque(IBinder token, boolean isOpaque) {
+ AppWindowToken wtoken = findAppWindowToken(token);
+ if (wtoken != null) {
+ WindowState win = wtoken.findMainWindow();
+ if (win != null) {
+ win.mWinAnimator.setOpaque(isOpaque);
+ }
+ }
+ }
+
boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
boolean visible, int transit, boolean performLayout) {
boolean delayed = false;
@@ -4536,7 +4547,9 @@
void removeAppFromTaskLocked(AppWindowToken wtoken) {
final Task task = mTaskIdToTask.get(wtoken.groupId);
if (task != null) {
- task.removeAppToken(wtoken);
+ if (!task.removeAppToken(wtoken)) {
+ Slog.e(TAG, "removeAppFromTaskLocked: token=" + wtoken + " not found.");
+ }
}
}
@@ -4572,6 +4585,8 @@
TAG, "Removing app " + wtoken + " delayed=" + delayed
+ " animation=" + wtoken.mAppAnimator.animation
+ " animating=" + wtoken.mAppAnimator.animating);
+ if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: "
+ + wtoken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack;
if (delayed) {
// set the token aside because it has an active animation to be finished
@@ -4587,9 +4602,6 @@
wtoken.mAppAnimator.animating = false;
removeAppFromTaskLocked(wtoken);
}
- if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
- "removeAppToken: " + wtoken);
-
wtoken.removed = true;
if (wtoken.startingData != null) {
@@ -4984,6 +4996,7 @@
+ " not found.");
}
if (stack.setBounds(bounds)) {
+ stack.resizeWindows();
stack.getDisplayContent().layoutNeeded = true;
performLayoutAndPlaceSurfacesLocked();
}
@@ -5757,7 +5770,11 @@
+ " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
}
}
- rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
+ // TODO: Replace 'false' in the following line with a variable that indicates
+ // whether the screenshot should use the identity transformation matrix
+ // (e.g., enable it when taking a screenshot for recents, since we might be in
+ // the middle of the rotation animation, but don't want a rotated recent image).
+ rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer, false);
}
} while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
if (retryCount > MAX_SCREENSHOT_RETRIES) Slog.i(TAG, "Screenshot max retries " +
@@ -8065,6 +8082,9 @@
final int numTokens = tokens.size();
for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
final AppWindowToken wtoken = tokens.get(tokenNdx);
+ if (wtoken.mDeferRemoval) {
+ continue;
+ }
i = reAddAppWindowsLocked(displayContent, i, wtoken);
}
}
@@ -9952,6 +9972,7 @@
}
// TODO(multidisplay): rotation on main screen only.
+ displayContent.updateDisplayInfo();
screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
mFxSession, inTransaction, mPolicy.isDefaultOrientationForced());
mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ffb17f1..f98b724 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1,4 +1,18 @@
-// Copyright 2012 Google Inc. All Rights Reserved.
+/*
+ * 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.wm;
@@ -490,6 +504,7 @@
private final Rect mWindowCrop = new Rect();
private boolean mShown = false;
private int mLayerStack;
+ private boolean mIsOpaque;
private final String mName;
public SurfaceTrace(SurfaceSession s,
@@ -575,6 +590,16 @@
}
@Override
+ public void setOpaque(boolean isOpaque) {
+ if (isOpaque != mIsOpaque) {
+ Slog.v(SURFACE_TAG, "setOpaque(" + isOpaque + "): OLD:" + this
+ + ". Called by " + Debug.getCallers(3));
+ mIsOpaque = isOpaque;
+ }
+ super.setOpaque(isOpaque);
+ }
+
+ @Override
public void hide() {
if (mShown) {
Slog.v(SURFACE_TAG, "hide: OLD:" + this + ". Called by " + Debug.getCallers(3));
@@ -620,7 +645,8 @@
+ mName + " (" + mLayerStack + "): shown=" + mShown + " layer=" + mLayer
+ " alpha=" + mSurfaceTraceAlpha + " " + mPosition.x + "," + mPosition.y
+ " " + mSize.x + "x" + mSize.y
- + " crop=" + mWindowCrop.toShortString();
+ + " crop=" + mWindowCrop.toShortString()
+ + " opaque=" + mIsOpaque;
}
}
@@ -1337,8 +1363,7 @@
Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
return;
}
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION setTransparentRegion");
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion");
SurfaceControl.openTransaction();
try {
if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
@@ -1364,8 +1389,7 @@
// transformation is being applied by the animation.
return;
}
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION setWallpaperOffset");
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
SurfaceControl.openTransaction();
try {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
@@ -1383,6 +1407,22 @@
}
}
+ void setOpaque(boolean isOpaque) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setOpaque");
+ SurfaceControl.openTransaction();
+ try {
+ if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "isOpaque=" + isOpaque,
+ null);
+ mSurfaceControl.setOpaque(isOpaque);
+ } finally {
+ SurfaceControl.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaque");
+ }
+ }
+
// This must be called while inside a transaction.
boolean performShowLocked() {
if (mWin.isHiddenFromUserLocked()) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 85f69a4..7675ba6 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -8,6 +8,7 @@
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+ $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 342515b..c26a516 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -36,6 +36,7 @@
#include <unistd.h>
#include <linux/ioctl.h>
#include <linux/android_alarm.h>
+#include <linux/rtc.h>
namespace android {
@@ -58,6 +59,7 @@
virtual ~AlarmImpl();
virtual int set(int type, struct timespec *ts) = 0;
+ virtual int setTime(struct timeval *tv) = 0;
virtual int waitForAlarm() = 0;
protected:
@@ -71,6 +73,7 @@
AlarmImplAlarmDriver(int fd) : AlarmImpl(&fd, 1) { }
int set(int type, struct timespec *ts);
+ int setTime(struct timeval *tv);
int waitForAlarm();
};
@@ -82,6 +85,7 @@
~AlarmImplTimerFd();
int set(int type, struct timespec *ts);
+ int setTime(struct timeval *tv);
int waitForAlarm();
private:
@@ -107,6 +111,19 @@
return ioctl(fds[0], ANDROID_ALARM_SET(type), ts);
}
+int AlarmImplAlarmDriver::setTime(struct timeval *tv)
+{
+ struct timespec ts;
+ int res;
+
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ res = ioctl(fds[0], ANDROID_ALARM_SET_RTC, &ts);
+ if (res < 0)
+ ALOGV("ANDROID_ALARM_SET_RTC ioctl failed: %s\n", strerror(errno));
+ return res;
+}
+
int AlarmImplAlarmDriver::waitForAlarm()
{
return ioctl(fds[0], ANDROID_ALARM_WAIT);
@@ -140,6 +157,50 @@
return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}
+int AlarmImplTimerFd::setTime(struct timeval *tv)
+{
+ struct rtc_time rtc;
+ struct tm tm, *gmtime_res;
+ int fd;
+ int res;
+
+ res = settimeofday(tv, NULL);
+ if (res < 0) {
+ ALOGV("settimeofday() failed: %s\n", strerror(errno));
+ return -1;
+ }
+
+ fd = open("/dev/rtc0", O_RDWR);
+ if (fd < 0) {
+ ALOGV("Unable to open RTC driver: %s\n", strerror(errno));
+ return res;
+ }
+
+ gmtime_res = gmtime_r(&tv->tv_sec, &tm);
+ if (!gmtime_res) {
+ ALOGV("gmtime_r() failed: %s\n", strerror(errno));
+ res = -1;
+ goto done;
+ }
+
+ memset(&rtc, 0, sizeof(rtc));
+ rtc.tm_sec = tm.tm_sec;
+ rtc.tm_min = tm.tm_min;
+ rtc.tm_hour = tm.tm_hour;
+ rtc.tm_mday = tm.tm_mday;
+ rtc.tm_mon = tm.tm_mon;
+ rtc.tm_year = tm.tm_year;
+ rtc.tm_wday = tm.tm_wday;
+ rtc.tm_yday = tm.tm_yday;
+ rtc.tm_isdst = tm.tm_isdst;
+ res = ioctl(fd, RTC_SET_TIME, &rtc);
+ if (res < 0)
+ ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
+done:
+ close(fd);
+ return res;
+}
+
int AlarmImplTimerFd::waitForAlarm()
{
epoll_event events[N_ANDROID_TIMERFDS];
@@ -168,6 +229,30 @@
return result;
}
+static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
+{
+ AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
+ struct timeval tv;
+ int ret;
+
+ if (millis <= 0 || millis / 1000LL >= INT_MAX) {
+ return -1;
+ }
+
+ tv.tv_sec = (time_t) (millis / 1000LL);
+ tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);
+
+ ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);
+
+ ret = impl->setTime(&tv);
+
+ if(ret < 0) {
+ ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
+ ret = -1;
+ }
+ return ret;
+}
+
static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
{
struct timezone tz;
@@ -309,6 +394,7 @@
{"close", "(J)V", (void*)android_server_AlarmManagerService_close},
{"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
{"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
+ {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
{"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
};
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 4a1b55d..163692b 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -73,7 +73,7 @@
SkSafeUnref(previousCanvas);
}
-static SkBitmap* com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
+static jlong com_android_server_AssetAtlasService_acquireCanvas(JNIEnv* env, jobject,
jobject canvas, jint width, jint height) {
SkBitmap* bitmap = new SkBitmap;
@@ -84,12 +84,13 @@
SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (*bitmap));
swapCanvasPtr(env, canvas, nativeCanvas);
- return bitmap;
+ return reinterpret_cast<jlong>(bitmap);
}
static void com_android_server_AssetAtlasService_releaseCanvas(JNIEnv* env, jobject,
- jobject canvas, SkBitmap* bitmap) {
+ jobject canvas, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
SkCanvas* nativeCanvas = SkNEW(SkCanvas);
swapCanvasPtr(env, canvas, nativeCanvas);
@@ -108,21 +109,22 @@
return result;
static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
- jobject graphicBuffer, SkBitmap* bitmap) {
+ jobject graphicBuffer, jlong bitmapHandle) {
+ SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
// The goal of this method is to copy the bitmap into the GraphicBuffer
// using the GPU to swizzle the texture content
sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
if (buffer != NULL) {
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (display == EGL_NO_DISPLAY) return false;
+ if (display == EGL_NO_DISPLAY) return JNI_FALSE;
EGLint major;
EGLint minor;
if (!eglInitialize(display, &major, &minor)) {
ALOGW("Could not initialize EGL");
- return false;
+ return JNI_FALSE;
}
// We're going to use a 1x1 pbuffer surface later on
@@ -143,13 +145,13 @@
ALOGW("Could not select EGL configuration");
eglReleaseThread();
eglTerminate(display);
- return false;
+ return JNI_FALSE;
}
if (configCount <= 0) {
ALOGW("Could not find EGL configuration");
eglReleaseThread();
eglTerminate(display);
- return false;
+ return JNI_FALSE;
}
// These objects are initialized below but the default "null"
@@ -164,7 +166,7 @@
EGLContext context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, attrs);
if (context == EGL_NO_CONTEXT) {
ALOGW("Could not create EGL context");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// Create the 1x1 pbuffer
@@ -172,12 +174,12 @@
surface = eglCreatePbufferSurface(display, configs[0], surfaceAttrs);
if (surface == EGL_NO_SURFACE) {
ALOGW("Could not create EGL surface");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
if (!eglMakeCurrent(display, surface, surface, context)) {
ALOGW("Could not change current EGL context");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// We use an EGLImage to access the content of the GraphicBuffer
@@ -188,7 +190,7 @@
EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
if (image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
glGenTextures(1, &texture);
@@ -196,7 +198,7 @@
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
if (glGetError() != GL_NO_ERROR) {
ALOGW("Could not create/bind texture");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// Upload the content of the bitmap in the GraphicBuffer
@@ -205,7 +207,7 @@
GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
if (glGetError() != GL_NO_ERROR) {
ALOGW("Could not upload to texture");
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// The fence is used to wait for the texture upload to finish
@@ -214,7 +216,7 @@
fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
if (fence == EGL_NO_SYNC_KHR) {
ALOGW("Could not create sync fence %#x", eglGetError());
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
@@ -223,13 +225,13 @@
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
ALOGW("Failed to wait for the fence %#x", eglGetError());
- CLEANUP_GL_AND_RETURN(false);
+ CLEANUP_GL_AND_RETURN(JNI_FALSE);
}
- CLEANUP_GL_AND_RETURN(true);
+ CLEANUP_GL_AND_RETURN(JNI_TRUE);
}
- return false;
+ return JNI_FALSE;
}
// ----------------------------------------------------------------------------
@@ -247,11 +249,11 @@
const char* const kClassPathName = "com/android/server/AssetAtlasService";
static JNINativeMethod gMethods[] = {
- { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)I",
+ { "nAcquireAtlasCanvas", "(Landroid/graphics/Canvas;II)J",
(void*) com_android_server_AssetAtlasService_acquireCanvas },
- { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;I)V",
+ { "nReleaseAtlasCanvas", "(Landroid/graphics/Canvas;J)V",
(void*) com_android_server_AssetAtlasService_releaseCanvas },
- { "nUploadAtlas", "(Landroid/view/GraphicBuffer;I)Z",
+ { "nUploadAtlas", "(Landroid/view/GraphicBuffer;J)Z",
(void*) com_android_server_AssetAtlasService_upload },
};
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index f1fa6cf..fc6de60 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -163,8 +163,10 @@
return NULL;
int fd = usb_device_get_fd(device);
- if (fd < 0)
+ if (fd < 0) {
+ usb_device_close(device);
return NULL;
+ }
int newFD = dup(fd);
usb_device_close(device);
diff --git a/services/core/jni/com_android_server_dreams_McuHal.cpp b/services/core/jni/com_android_server_dreams_McuHal.cpp
new file mode 100644
index 0000000..a6d9297
--- /dev/null
+++ b/services/core/jni/com_android_server_dreams_McuHal.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "McuHal"
+
+//#define LOG_NDEBUG 0
+
+#include "JNIHelp.h"
+#include "jni.h"
+
+#include <ScopedUtfChars.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <hardware/mcu.h>
+
+namespace android {
+
+static jlong nativeOpen(JNIEnv* env, jclass clazz) {
+ mcu_module_t* module = NULL;
+ status_t err = hw_get_module(MCU_HARDWARE_MODULE_ID,
+ (hw_module_t const**)&module);
+ if (err) {
+ ALOGE("Couldn't load %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ err = module->init(module);
+ if (err) {
+ ALOGE("Couldn't initialize %s module (%s)", MCU_HARDWARE_MODULE_ID, strerror(-err));
+ return 0;
+ }
+
+ return reinterpret_cast<jlong>(module);
+}
+
+static jbyteArray nativeSendMessage(JNIEnv* env, jclass clazz,
+ jlong ptr, jstring msgStr, jbyteArray argArray) {
+ mcu_module_t* module = reinterpret_cast<mcu_module_t*>(ptr);
+
+ ScopedUtfChars msg(env, msgStr);
+ ALOGV("Sending message %s to MCU", msg.c_str());
+
+ void* result = NULL;
+ size_t resultSize = 0;
+ status_t err;
+ if (argArray) {
+ ScopedByteArrayRO arg(env, argArray);
+ err = module->sendMessage(module, msg.c_str(), arg.get(), arg.size(),
+ &result, &resultSize);
+ } else {
+ err = module->sendMessage(module, msg.c_str(), NULL, 0, &result, &resultSize);
+ }
+ if (err) {
+ ALOGE("Couldn't send message to MCU (%s)", strerror(-err));
+ return NULL;
+ }
+
+ if (!result) {
+ return NULL;
+ }
+
+ jbyteArray resultArray = env->NewByteArray(resultSize);
+ if (resultArray) {
+ env->SetByteArrayRegion(resultArray, 0, resultSize, static_cast<jbyte*>(result));
+ }
+ free(result);
+ return resultArray;
+}
+
+static JNINativeMethod gMcuHalMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeOpen", "()J",
+ (void*) nativeOpen },
+ { "nativeSendMessage", "(JLjava/lang/String;[B)[B",
+ (void*) nativeSendMessage },
+};
+
+int register_android_server_dreams_McuHal(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/dreams/McuHal",
+ gMcuHalMethods, NELEM(gMcuHalMethods));
+ LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+ return 0;
+}
+
+} /* namespace android */
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 9fe0082..0207c55 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -151,8 +151,6 @@
enum {
WM_ACTION_PASS_TO_USER = 1,
- WM_ACTION_WAKE_UP = 2,
- WM_ACTION_GO_TO_SLEEP = 4,
};
@@ -844,7 +842,7 @@
JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
- policyFlags);
+ when, policyFlags);
if (checkAndClearExceptionFromCallback(env,
"interceptMotionBeforeQueueingWhenScreenOff")) {
wmActions = 0;
@@ -860,20 +858,6 @@
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
- if (wmActions & WM_ACTION_GO_TO_SLEEP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("handleInterceptActions: Going to sleep.");
-#endif
- android_server_PowerManagerService_goToSleep(when);
- }
-
- if (wmActions & WM_ACTION_WAKE_UP) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- ALOGD("handleInterceptActions: Waking up.");
-#endif
- android_server_PowerManagerService_wakeUp(when);
- }
-
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
@@ -1412,7 +1396,7 @@
GET_METHOD_ID(gServiceClassInfo.interceptMotionBeforeQueueingWhenScreenOff,
clazz,
- "interceptMotionBeforeQueueingWhenScreenOff", "(I)I");
+ "interceptMotionBeforeQueueingWhenScreenOff", "(JI)I");
GET_METHOD_ID(gServiceClassInfo.interceptKeyBeforeDispatching, clazz,
"interceptKeyBeforeDispatching",
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index efc34a2..00986d5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -36,6 +36,7 @@
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
+int register_android_server_dreams_McuHal(JNIEnv* env);
};
using namespace android;
@@ -67,7 +68,7 @@
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
-
+ register_android_server_dreams_McuHal(env);
return JNI_VERSION_1_4;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bb96544..f186b2c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1315,9 +1315,7 @@
}
if (admin.getUid() != Binder.getCallingUid()) {
// If trying to remove device owner, refuse when the caller is not the owner.
- if (mDeviceOwner != null
- && adminReceiver.getPackageName().equals(
- mDeviceOwner.getDeviceOwnerPackageName())) {
+ if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
}
mContext.enforceCallingOrSelfPermission(
@@ -2793,6 +2791,7 @@
}
synchronized (this) {
return mDeviceOwner != null
+ && mDeviceOwner.hasDeviceOwner()
&& mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
}
}
@@ -2830,6 +2829,14 @@
return false;
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
+
+ UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ if (um.getUserInfo(userHandle) == null) {
+ // User doesn't exist.
+ throw new IllegalArgumentException(
+ "Attempted to set profile owner for invalid userId: " + userHandle);
+ }
+
if (packageName == null
|| !DeviceOwner.isInstalledForUser(packageName, userHandle)) {
throw new IllegalArgumentException("Package name " + packageName
@@ -2958,4 +2965,66 @@
}
}
}
+
+ private boolean isProfileOwner(String packageName, int userId) {
+ String profileOwnerPackage = getProfileOwner(userId);
+ // TODO: make public and connect with isProfileOwnerApp in DPM
+ return profileOwnerPackage != null && profileOwnerPackage.equals(packageName);
+ }
+
+ public void addPersistentPreferredActivity(ComponentName admin, IntentFilter filter,
+ ComponentName activity) {
+ int callingUserId = UserHandle.getCallingUserId();
+ Slog.d(LOG_TAG,"called by user " + callingUserId);
+ synchronized (this) {
+ ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId);
+ if (aa == null) {
+ throw new SecurityException("No active admin " + admin);
+ } else {
+ if (isProfileOwner(admin.getPackageName(), callingUserId)
+ || isDeviceOwner(admin.getPackageName())) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ long id = Binder.clearCallingIdentity();
+ try {
+ pm.addPersistentPreferredActivity(filter, activity, callingUserId);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ } else {
+ throw new SecurityException("Admin " + admin +
+ "is not device owner or profile owner" );
+ }
+ }
+ }
+ }
+
+ public void clearPackagePersistentPreferredActivities(ComponentName admin,
+ String packageName) {
+ int callingUserId = UserHandle.getCallingUserId();
+ Slog.d(LOG_TAG,"called by user " + callingUserId);
+ synchronized (this) {
+ ActiveAdmin aa = getActiveAdminUncheckedLocked(admin, callingUserId);
+ if (aa == null) {
+ throw new SecurityException("No active admin " + admin);
+ } else {
+ if (isProfileOwner(admin.getPackageName(), callingUserId)
+ || isDeviceOwner(admin.getPackageName())) {
+ IPackageManager pm = AppGlobals.getPackageManager();
+ long id = Binder.clearCallingIdentity();
+ try{
+ pm.clearPackagePersistentPreferredActivities(packageName, callingUserId);
+ } catch (RemoteException re) {
+ // Shouldn't happen
+ } finally {
+ restoreCallingIdentity(id);
+ }
+ } else {
+ throw new SecurityException("Admin " + admin +
+ "is not device owner or profile owner" );
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 85e5e23..91d77fb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -62,6 +62,7 @@
import com.android.server.lights.LightsManager;
import com.android.server.lights.LightsService;
import com.android.server.media.MediaRouterService;
+import com.android.server.media.MediaSessionService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
import com.android.server.notification.NotificationManagerService;
@@ -74,7 +75,6 @@
import com.android.server.search.SearchManagerService;
import com.android.server.statusbar.StatusBarManagerService;
import com.android.server.storage.DeviceStorageMonitorService;
-import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightService;
import com.android.server.usb.UsbService;
import com.android.server.wallpaper.WallpaperManagerService;
@@ -111,6 +111,12 @@
"com.android.server.appwidget.AppWidgetService";
private static final String PRINT_MANAGER_SERVICE_CLASS =
"com.android.server.print.PrintManagerService";
+ private static final String USB_SERVICE_CLASS =
+ "com.android.server.usb.UsbService$Lifecycle";
+ private static final String WIFI_SERVICE_CLASS =
+ "com.android.server.wifi.WifiService";
+ private static final String WIFI_P2P_SERVICE_CLASS =
+ "com.android.server.wifi.p2p.WifiP2pService";
private final int mFactoryTestMode;
private Timer mProfilerSnapshotTimer;
@@ -303,7 +309,6 @@
DockObserver dock = null;
UsbService usb = null;
SerialService serial = null;
- TwilightManager twilight = null;
RecognitionManagerService recognition = null;
NetworkTimeUpdateService networkTimeUpdater = null;
CommonTimeManagementService commonTimeMgmtService = null;
@@ -460,7 +465,6 @@
CountryDetectorService countryDetector = null;
TextServicesManagerService tsms = null;
LockSettingsService lockSettings = null;
- DreamManagerService dreamy = null;
AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
@@ -532,9 +536,8 @@
}
try {
- if (pm.hasSystemFeature("android.software.device_admin")) {
- mSystemServiceManager.startServiceIfExists(
- DEVICE_POLICY_MANAGER_SERVICE_CLASS);
+ if (pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
+ mSystemServiceManager.startService(DEVICE_POLICY_MANAGER_SERVICE_CLASS);
}
} catch (Throwable e) {
reportWtf("starting DevicePolicyService", e);
@@ -602,17 +605,13 @@
}
try {
- Slog.i(TAG, "Wi-Fi P2pService");
- mSystemServiceManager.startServiceIfExists(
- "com.android.server.wifi.p2p.WifiP2pService");
+ mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
} catch (Throwable e) {
reportWtf("starting Wi-Fi P2pService", e);
}
try {
- Slog.i(TAG, "Wi-Fi Service");
- mSystemServiceManager.startServiceIfExists(
- "com.android.server.wifi.WifiService");
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
} catch (Throwable e) {
reportWtf("starting Wi-Fi Service", e);
}
@@ -757,10 +756,11 @@
if (!disableNonCoreServices) {
try {
- Slog.i(TAG, "USB Service");
- // Manage USB host and device support
- usb = new UsbService(context);
- ServiceManager.addService(Context.USB_SERVICE, usb);
+ if (pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST) ||
+ pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY)) {
+ // Manage USB host and device support
+ mSystemServiceManager.startService(USB_SERVICE_CLASS);
+ }
} catch (Throwable e) {
reportWtf("starting UsbService", e);
}
@@ -776,22 +776,21 @@
}
mSystemServiceManager.startService(TwilightService.class);
- twilight = LocalServices.getService(TwilightManager.class);
mSystemServiceManager.startService(UiModeManagerService.class);
if (!disableNonCoreServices) {
try {
- if (pm.hasSystemFeature("android.software.backup")) {
- mSystemServiceManager.startServiceIfExists(BACKUP_MANAGER_SERVICE_CLASS);
+ if (pm.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
+ mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
}
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Backup Service", e);
}
try {
- if (pm.hasSystemFeature("android.software.app_widgets")) {
- mSystemServiceManager.startServiceIfExists(APPWIDGET_SERVICE_CLASS);
+ if (pm.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
}
} catch (Throwable e) {
reportWtf("starting AppWidget Service", e);
@@ -852,16 +851,9 @@
}
}
- if (!disableNonCoreServices &&
- context.getResources().getBoolean(R.bool.config_dreamsSupported)) {
- try {
- Slog.i(TAG, "Dreams Service");
- // Dreams (interactive idle-time views, a/k/a screen savers)
- dreamy = new DreamManagerService(context);
- ServiceManager.addService(DreamService.DREAM_SERVICE, dreamy);
- } catch (Throwable e) {
- reportWtf("starting DreamManagerService", e);
- }
+ if (!disableNonCoreServices) {
+ // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
+ mSystemServiceManager.startService(DreamManagerService.class);
}
if (!disableNonCoreServices) {
@@ -882,13 +874,20 @@
}
try {
- if (pm.hasSystemFeature("android.software.print")) {
- mSystemServiceManager.startServiceIfExists(PRINT_MANAGER_SERVICE_CLASS);
+ if (pm.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
+ mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}
} catch (Throwable e) {
reportWtf("starting Print Service", e);
}
+ try {
+ Slog.i(TAG, "MediaSessionService");
+ mSystemServiceManager.startService(MediaSessionService.class);
+ } catch (Throwable e) {
+ reportWtf("starting MediaSessionService", e);
+ }
+
if (!disableNonCoreServices) {
try {
Slog.i(TAG, "Media Router Service");
@@ -956,7 +955,7 @@
try {
// TODO: use boot phase
- mPowerManagerService.systemReady(twilight, dreamy);
+ mPowerManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
@@ -975,7 +974,6 @@
}
// These are needed to propagate to the runnable below.
- final Context contextF = context;
final MountService mountServiceF = mountService;
final BatteryService batteryF = battery;
final NetworkManagementService networkManagementF = networkManagement;
@@ -983,7 +981,6 @@
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
final ConnectivityService connectivityF = connectivity;
final DockObserver dockF = dock;
- final UsbService usbF = usb;
final WallpaperManagerService wallpaperF = wallpaper;
final InputMethodManagerService immF = imm;
final RecognitionManagerService recognitionF = recognition;
@@ -993,7 +990,6 @@
final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
final TextServicesManagerService textServiceManagerServiceF = tsms;
final StatusBarManagerService statusBarF = statusBar;
- final DreamManagerService dreamyF = dreamy;
final AssetAtlasService atlasF = atlas;
final InputManagerService inputManagerF = inputManager;
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
@@ -1005,8 +1001,11 @@
// started launching the initial applications), for us to complete our
// initialization.
mActivityManagerService.systemReady(new Runnable() {
+ @Override
public void run() {
Slog.i(TAG, "Making services ready");
+ mSystemServiceManager.startBootPhase(
+ SystemService.PHASE_ACTIVITY_MANAGER_READY);
try {
mActivityManagerService.startObservingNativeCrashes();
@@ -1014,7 +1013,7 @@
reportWtf("observing native crashes", e);
}
try {
- startSystemUi(contextF);
+ startSystemUi(context);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
@@ -1054,11 +1053,6 @@
reportWtf("making Dock Service ready", e);
}
try {
- if (usbF != null) usbF.systemReady();
- } catch (Throwable e) {
- reportWtf("making USB Service ready", e);
- }
- try {
if (recognitionF != null) recognitionF.systemReady();
} catch (Throwable e) {
reportWtf("making Recognition Service ready", e);
@@ -1067,7 +1061,8 @@
// It is now okay to let the various system services start their
// third party code...
- mSystemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+ mSystemServiceManager.startBootPhase(
+ SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
try {
if (wallpaperF != null) wallpaperF.systemRunning();
@@ -1095,7 +1090,9 @@
reportWtf("Notifying NetworkTimeService running", e);
}
try {
- if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemRunning();
+ if (commonTimeMgmtServiceF != null) {
+ commonTimeMgmtServiceF.systemRunning();
+ }
} catch (Throwable e) {
reportWtf("Notifying CommonTimeManagementService running", e);
}
@@ -1106,11 +1103,6 @@
reportWtf("Notifying TextServicesManagerService running", e);
}
try {
- if (dreamyF != null) dreamyF.systemRunning();
- } catch (Throwable e) {
- reportWtf("Notifying DreamManagerService running", e);
- }
- try {
if (atlasF != null) atlasF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying AssetAtlasService running", e);
@@ -1121,13 +1113,11 @@
} catch (Throwable e) {
reportWtf("Notifying InputManagerService running", e);
}
-
try {
if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying TelephonyRegistry running", e);
}
-
try {
if (mediaRouterF != null) mediaRouterF.systemRunning();
} catch (Throwable e) {
diff --git a/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
new file mode 100644
index 0000000..33f604d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/location/LocationRequestStatisticsTest.java
@@ -0,0 +1,175 @@
+package com.android.server.location;
+
+import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
+import com.android.server.location.LocationRequestStatistics.PackageStatistics;
+
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+
+/**
+ * Unit tests for {@link LocationRequestStatistics}.
+ */
+public class LocationRequestStatisticsTest extends AndroidTestCase {
+ private static final String PACKAGE1 = "package1";
+ private static final String PACKAGE2 = "package2";
+ private static final String PROVIDER1 = "provider1";
+ private static final String PROVIDER2 = "provider2";
+ private static final long INTERVAL1 = 5000;
+ private static final long INTERVAL2 = 100000;
+
+ private LocationRequestStatistics mStatistics;
+ private long mStartElapsedRealtimeMs;
+
+ @Override
+ public void setUp() {
+ mStatistics = new LocationRequestStatistics();
+ mStartElapsedRealtimeMs = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Tests that adding a single package works correctly.
+ */
+ public void testSinglePackage() {
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+
+ assertEquals(1, mStatistics.statistics.size());
+ PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
+ assertEquals(PACKAGE1, key.packageName);
+ assertEquals(PROVIDER1, key.providerName);
+ PackageStatistics stats = mStatistics.statistics.values().iterator().next();
+ verifyStatisticsTimes(stats);
+ assertEquals(INTERVAL1, stats.getFastestIntervalMs());
+ assertEquals(INTERVAL1, stats.getSlowestIntervalMs());
+ assertTrue(stats.isActive());
+ }
+
+ /**
+ * Tests that adding a single package works correctly when it is stopped and restarted.
+ */
+ public void testSinglePackage_stopAndRestart() {
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+
+ assertEquals(1, mStatistics.statistics.size());
+ PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
+ assertEquals(PACKAGE1, key.packageName);
+ assertEquals(PROVIDER1, key.providerName);
+ PackageStatistics stats = mStatistics.statistics.values().iterator().next();
+ verifyStatisticsTimes(stats);
+ assertEquals(INTERVAL1, stats.getFastestIntervalMs());
+ assertEquals(INTERVAL1, stats.getSlowestIntervalMs());
+ assertTrue(stats.isActive());
+
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+ assertFalse(stats.isActive());
+ }
+
+ /**
+ * Tests that adding a single package works correctly when multiple intervals are used.
+ */
+ public void testSinglePackage_multipleIntervals() {
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL2);
+
+ assertEquals(1, mStatistics.statistics.size());
+ PackageProviderKey key = mStatistics.statistics.keySet().iterator().next();
+ assertEquals(PACKAGE1, key.packageName);
+ assertEquals(PROVIDER1, key.providerName);
+ PackageStatistics stats = mStatistics.statistics.values().iterator().next();
+ verifyStatisticsTimes(stats);
+ assertEquals(INTERVAL1, stats.getFastestIntervalMs());
+ assertTrue(stats.isActive());
+
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+ assertTrue(stats.isActive());
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+ assertFalse(stats.isActive());
+ }
+
+ /**
+ * Tests that adding a single package works correctly when multiple providers are used.
+ */
+ public void testSinglePackage_multipleProviders() {
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2);
+
+ assertEquals(2, mStatistics.statistics.size());
+ PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1);
+ PackageStatistics stats1 = mStatistics.statistics.get(key1);
+ verifyStatisticsTimes(stats1);
+ assertEquals(INTERVAL1, stats1.getSlowestIntervalMs());
+ assertEquals(INTERVAL1, stats1.getFastestIntervalMs());
+ assertTrue(stats1.isActive());
+ PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, PROVIDER2);
+ PackageStatistics stats2 = mStatistics.statistics.get(key2);
+ verifyStatisticsTimes(stats2);
+ assertEquals(INTERVAL2, stats2.getSlowestIntervalMs());
+ assertEquals(INTERVAL2, stats2.getFastestIntervalMs());
+ assertTrue(stats2.isActive());
+
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+ assertFalse(stats1.isActive());
+ assertTrue(stats2.isActive());
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER2);
+ assertFalse(stats1.isActive());
+ assertFalse(stats2.isActive());
+ }
+
+ /**
+ * Tests that adding multiple packages works correctly.
+ */
+ public void testMultiplePackages() {
+ mStatistics.startRequesting(PACKAGE1, PROVIDER1, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL1);
+ mStatistics.startRequesting(PACKAGE1, PROVIDER2, INTERVAL2);
+ mStatistics.startRequesting(PACKAGE2, PROVIDER1, INTERVAL1);
+
+ assertEquals(3, mStatistics.statistics.size());
+ PackageProviderKey key1 = new PackageProviderKey(PACKAGE1, PROVIDER1);
+ PackageStatistics stats1 = mStatistics.statistics.get(key1);
+ verifyStatisticsTimes(stats1);
+ assertEquals(INTERVAL1, stats1.getSlowestIntervalMs());
+ assertEquals(INTERVAL1, stats1.getFastestIntervalMs());
+ assertTrue(stats1.isActive());
+
+ PackageProviderKey key2 = new PackageProviderKey(PACKAGE1, PROVIDER2);
+ PackageStatistics stats2 = mStatistics.statistics.get(key2);
+ verifyStatisticsTimes(stats2);
+ assertEquals(INTERVAL2, stats2.getSlowestIntervalMs());
+ assertEquals(INTERVAL1, stats2.getFastestIntervalMs());
+ assertTrue(stats2.isActive());
+
+ PackageProviderKey key3 = new PackageProviderKey(PACKAGE2, PROVIDER1);
+ PackageStatistics stats3 = mStatistics.statistics.get(key3);
+ verifyStatisticsTimes(stats3);
+ assertEquals(INTERVAL1, stats3.getSlowestIntervalMs());
+ assertEquals(INTERVAL1, stats3.getFastestIntervalMs());
+ assertTrue(stats3.isActive());
+
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER1);
+ assertFalse(stats1.isActive());
+ assertTrue(stats2.isActive());
+ assertTrue(stats3.isActive());
+
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER2);
+ assertFalse(stats1.isActive());
+ assertTrue(stats2.isActive());
+ assertTrue(stats3.isActive());
+ mStatistics.stopRequesting(PACKAGE1, PROVIDER2);
+ assertFalse(stats2.isActive());
+
+ mStatistics.stopRequesting(PACKAGE2, PROVIDER1);
+ assertFalse(stats1.isActive());
+ assertFalse(stats2.isActive());
+ assertFalse(stats3.isActive());
+ }
+
+ private void verifyStatisticsTimes(PackageStatistics stats) {
+ long durationMs = stats.getDurationMs();
+ long timeSinceFirstRequestMs = stats.getTimeSinceFirstRequestMs();
+ long maxDeltaMs = SystemClock.elapsedRealtime() - mStartElapsedRealtimeMs;
+ assertTrue("Duration is too large", durationMs <= maxDeltaMs);
+ assertTrue("Time since first request is too large", timeSinceFirstRequestMs <= maxDeltaMs);
+ }
+}
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
new file mode 100644
index 0000000..feabf0a
--- /dev/null
+++ b/services/usb/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.usb
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+LOCAL_JAVA_LIBRARIES := services.core
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/core/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java
similarity index 100%
rename from services/core/java/com/android/server/usb/UsbDebuggingManager.java
rename to services/usb/java/com/android/server/usb/UsbDebuggingManager.java
diff --git a/services/core/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
similarity index 95%
rename from services/core/java/com/android/server/usb/UsbDeviceManager.java
rename to services/usb/java/com/android/server/usb/UsbDeviceManager.java
index c1a3646..b925856 100644
--- a/services/core/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -99,6 +99,13 @@
// which need debouncing.
private static final int UPDATE_DELAY = 1000;
+ // Time we received a request to enter USB accessory mode
+ private long mAccessoryModeRequestTime = 0;
+
+ // Timeout for entering USB request mode.
+ // Request is cancelled if host does not configure device within 10 seconds.
+ private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
+
private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
private UsbHandler mHandler;
@@ -206,6 +213,8 @@
}
private void startAccessoryMode() {
+ if (!mHasUsbAccessory) return;
+
mAccessoryStrings = nativeGetAccessoryStrings();
boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
// don't start accessory mode if our mandatory strings have not been set
@@ -224,6 +233,7 @@
}
if (functions != null) {
+ mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
setCurrentFunctions(functions, false);
}
}
@@ -452,6 +462,8 @@
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
+ if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
+ + " makeDefault: " + makeDefault);
// Do not update persystent.sys.usb.config if the device is booted up
// with OEM specific mode.
@@ -513,9 +525,17 @@
}
private void updateCurrentAccessory() {
- if (!mHasUsbAccessory) return;
+ // We are entering accessory mode if we have received a request from the host
+ // and the request has not timed out yet.
+ boolean enteringAccessoryMode =
+ mAccessoryModeRequestTime > 0 &&
+ SystemClock.elapsedRealtime() <
+ mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
- if (mConfigured) {
+ if (mConfigured && enteringAccessoryMode) {
+ // successfully entered accessory mode
+ mAccessoryModeRequestTime = 0;
+
if (mAccessoryStrings != null) {
mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
@@ -526,7 +546,7 @@
} else {
Slog.e(TAG, "nativeGetAccessoryStrings failed");
}
- } else if (!mConnected) {
+ } else if (!enteringAccessoryMode) {
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
@@ -556,6 +576,8 @@
}
}
+ if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected
+ + " configured: " + mConfigured);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -595,9 +617,7 @@
if (containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
- }
-
- if (!mConnected) {
+ } else if (!mConnected) {
// restore defaults when USB is disconnected
setEnabledFunctions(mDefaultFunctions, false);
}
@@ -697,6 +717,7 @@
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
notification.setLatestEventInfo(mContext, title, message, pi);
+ notification.visibility = Notification.VISIBILITY_PUBLIC;
mNotificationManager.notifyAsUser(null, id, notification,
UserHandle.ALL);
mUsbNotificationId = id;
@@ -732,6 +753,7 @@
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
notification.setLatestEventInfo(mContext, title, message, pi);
+ notification.visibility = Notification.VISIBILITY_PUBLIC;
mAdbNotificationShown = true;
mNotificationManager.notifyAsUser(null, id, notification,
UserHandle.ALL);
@@ -808,7 +830,7 @@
if (mOemModeMap == null) {
mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
}
- List overrideList = mOemModeMap.get(items[0]);
+ List<Pair<String, String>> overrideList = mOemModeMap.get(items[0]);
if (overrideList == null) {
overrideList = new LinkedList<Pair<String, String>>();
mOemModeMap.put(items[0], overrideList);
diff --git a/services/core/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
similarity index 100%
rename from services/core/java/com/android/server/usb/UsbHostManager.java
rename to services/usb/java/com/android/server/usb/UsbHostManager.java
diff --git a/services/core/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
similarity index 94%
rename from services/core/java/com/android/server/usb/UsbService.java
rename to services/usb/java/com/android/server/usb/UsbService.java
index 36669b1..b6ae192 100644
--- a/services/core/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -32,6 +32,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemService;
import java.io.File;
import java.io.FileDescriptor;
@@ -43,6 +44,28 @@
* support is delegated to UsbDeviceManager.
*/
public class UsbService extends IUsbManager.Stub {
+
+ public static class Lifecycle extends SystemService {
+ private UsbService mUsbService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ mUsbService = new UsbService(getContext());
+ publishBinderService(Context.USB_SERVICE, mUsbService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ mUsbService.systemReady();
+ }
+ }
+ }
+
private static final String TAG = "UsbService";
private final Context mContext;
diff --git a/services/core/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
similarity index 100%
rename from services/core/java/com/android/server/usb/UsbSettingsManager.java
rename to services/usb/java/com/android/server/usb/UsbSettingsManager.java
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
new file mode 100644
index 0000000..323e0ac
--- /dev/null
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -0,0 +1,108 @@
+/*
+ * 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.telephony;
+
+/**
+ * Contains disconnect call causes generated by the
+ * framework and the RIL.
+ *
+ * @hide
+ */
+public class DisconnectCause {
+
+ /** The disconnect cause is not valid (Not received a disconnect cause) */
+ public static final int NOT_VALID = -1;
+ /** Has not yet disconnected */
+ public static final int NOT_DISCONNECTED = 0;
+ /** An incoming call that was missed and never answered */
+ public static final int INCOMING_MISSED = 1;
+ /** Normal; Remote hangup*/
+ public static final int NORMAL = 2;
+ /** Normal; Local hangup */
+ public static final int LOCAL = 3;
+ /** Outgoing call to busy line */
+ public static final int BUSY = 4;
+ /** Outgoing call to congested network */
+ public static final int CONGESTION = 5;
+ /** Not presently used */
+ public static final int MMI = 6;
+ /** Invalid dial string */
+ public static final int INVALID_NUMBER = 7;
+ /** Cannot reach the peer */
+ public static final int NUMBER_UNREACHABLE = 8;
+ /** Cannot reach the server */
+ public static final int SERVER_UNREACHABLE = 9;
+ /** Invalid credentials */
+ public static final int INVALID_CREDENTIALS = 10;
+ /** Calling from out of network is not allowed */
+ public static final int OUT_OF_NETWORK = 11;
+ /** Server error */
+ public static final int SERVER_ERROR = 12;
+ /** Client timed out */
+ public static final int TIMED_OUT = 13;
+ /** Client went out of network range */
+ public static final int LOST_SIGNAL = 14;
+ /** GSM or CDMA ACM limit exceeded */
+ public static final int LIMIT_EXCEEDED = 15;
+ /** An incoming call that was rejected */
+ public static final int INCOMING_REJECTED = 16;
+ /** Radio is turned off explicitly */
+ public static final int POWER_OFF = 17;
+ /** Out of service */
+ public static final int OUT_OF_SERVICE = 18;
+ /** No ICC, ICC locked, or other ICC error */
+ public static final int ICC_ERROR = 19;
+ /** Call was blocked by call barring */
+ public static final int CALL_BARRED = 20;
+ /** Call was blocked by fixed dial number */
+ public static final int FDN_BLOCKED = 21;
+ /** Call was blocked by restricted all voice access */
+ public static final int CS_RESTRICTED = 22;
+ /** Call was blocked by restricted normal voice access */
+ public static final int CS_RESTRICTED_NORMAL = 23;
+ /** Call was blocked by restricted emergency voice access */
+ public static final int CS_RESTRICTED_EMERGENCY = 24;
+ /** Unassigned number */
+ public static final int UNOBTAINABLE_NUMBER = 25;
+ /** MS is locked until next power cycle */
+ public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 26;
+ /** Drop call*/
+ public static final int CDMA_DROP = 27;
+ /** INTERCEPT order received, MS state idle entered */
+ public static final int CDMA_INTERCEPT = 28;
+ /** MS has been redirected, call is cancelled */
+ public static final int CDMA_REORDER = 29;
+ /** Service option rejection */
+ public static final int CDMA_SO_REJECT = 30;
+ /** Requested service is rejected, retry delay is set */
+ public static final int CDMA_RETRY_ORDER = 31;
+ /** Unable to obtain access to the CDMA system */
+ public static final int CDMA_ACCESS_FAILURE = 32;
+ /** Not a preempted call */
+ public static final int CDMA_PREEMPTED = 33;
+ /** Not an emergency call */
+ public static final int CDMA_NOT_EMERGENCY = 34;
+ /** Access Blocked by CDMA network */
+ public static final int CDMA_ACCESS_BLOCKED = 35;
+ /** Unknown error or not specified */
+ public static final int ERROR_UNSPECIFIED = 36;
+
+ /** Private constructor to avoid class instantiation. */
+ private DisconnectCause() {
+ // Do nothing.
+ }
+}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index d34c55c..bb3f132 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -23,6 +23,9 @@
import android.telephony.SignalStrength;
import android.telephony.CellLocation;
import android.telephony.CellInfo;
+import android.telephony.Rlog;
+import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
import com.android.internal.telephony.IPhoneStateListener;
@@ -164,6 +167,27 @@
*/
public static final int LISTEN_CELL_INFO = 0x00000400;
+ /**
+ * Listen for precise changes and fails to the device calls (cellular).
+ * {@more}
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE}
+ *
+ * @hide
+ */
+ public static final int LISTEN_PRECISE_CALL_STATE = 0x00000800;
+
+ /**
+ * Listen for precise changes and fails on the data connection (cellular).
+ * {@more}
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE}
+ *
+ * @see #onPreciseDataConnectionStateChanged
+ * @hide
+ */
+ public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE = 0x00001000;
+
public PhoneStateListener() {
}
@@ -292,6 +316,25 @@
}
/**
+ * Callback invoked when precise device call state changes.
+ *
+ * @hide
+ */
+ public void onPreciseCallStateChanged(PreciseCallState callState) {
+ // default implementation empty
+ }
+
+ /**
+ * Callback invoked when data connection state changes with precise information.
+ *
+ * @hide
+ */
+ public void onPreciseDataConnectionStateChanged(
+ PreciseDataConnectionState dataConnectionState) {
+ // default implementation empty
+ }
+
+ /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
*/
@@ -343,6 +386,16 @@
public void onCellInfoChanged(List<CellInfo> cellInfo) {
Message.obtain(mHandler, LISTEN_CELL_INFO, 0, 0, cellInfo).sendToTarget();
}
+
+ public void onPreciseCallStateChanged(PreciseCallState callState) {
+ Message.obtain(mHandler, LISTEN_PRECISE_CALL_STATE, 0, 0, callState).sendToTarget();
+ }
+
+ public void onPreciseDataConnectionStateChanged(
+ PreciseDataConnectionState dataConnectionState) {
+ Message.obtain(mHandler, LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0,
+ dataConnectionState).sendToTarget();
+ }
};
Handler mHandler = new Handler() {
@@ -382,6 +435,12 @@
break;
case LISTEN_CELL_INFO:
PhoneStateListener.this.onCellInfoChanged((List<CellInfo>)msg.obj);
+ break;
+ case LISTEN_PRECISE_CALL_STATE:
+ PhoneStateListener.this.onPreciseCallStateChanged((PreciseCallState)msg.obj);
+ break;
+ case LISTEN_PRECISE_DATA_CONNECTION_STATE:
+ PhoneStateListener.this.onPreciseDataConnectionStateChanged((PreciseDataConnectionState)msg.obj);
}
}
};
diff --git a/telephony/java/android/telephony/PreciseCallState.aidl b/telephony/java/android/telephony/PreciseCallState.aidl
new file mode 100644
index 0000000..447f29b
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseCallState.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable PreciseCallState;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/PreciseCallState.java b/telephony/java/android/telephony/PreciseCallState.java
new file mode 100644
index 0000000..a85df15
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseCallState.java
@@ -0,0 +1,311 @@
+/*
+ * 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.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+import android.telephony.DisconnectCause;
+import android.telephony.PreciseDisconnectCause;
+
+/**
+ * Contains precise call state and call fail causes generated by the
+ * framework and the RIL.
+ *
+ * The following call information is included in returned PreciseCallState:
+ *
+ * <ul>
+ * <li>Ringing call state.
+ * <li>Foreground call state.
+ * <li>Background call state.
+ * <li>Disconnect cause; generated by the framework.
+ * <li>Precise disconnect cause; generated by the RIL.
+ * </ul>
+ *
+ * @hide
+ */
+public class PreciseCallState implements Parcelable {
+
+ /** Call state is not valid (Not received a call state). */
+ public static final int PRECISE_CALL_STATE_NOT_VALID = -1;
+ /** Call state: No activity. */
+ public static final int PRECISE_CALL_STATE_IDLE = 0;
+ /** Call state: Active. */
+ public static final int PRECISE_CALL_STATE_ACTIVE = 1;
+ /** Call state: On hold. */
+ public static final int PRECISE_CALL_STATE_HOLDING = 2;
+ /** Call state: Dialing. */
+ public static final int PRECISE_CALL_STATE_DIALING = 3;
+ /** Call state: Alerting. */
+ public static final int PRECISE_CALL_STATE_ALERTING = 4;
+ /** Call state: Incoming. */
+ public static final int PRECISE_CALL_STATE_INCOMING = 5;
+ /** Call state: Waiting. */
+ public static final int PRECISE_CALL_STATE_WAITING = 6;
+ /** Call state: Disconnected. */
+ public static final int PRECISE_CALL_STATE_DISCONNECTED = 7;
+ /** Call state: Disconnecting. */
+ public static final int PRECISE_CALL_STATE_DISCONNECTING = 8;
+
+ private int mRingingCallState = PRECISE_CALL_STATE_NOT_VALID;
+ private int mForegroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+ private int mBackgroundCallState = PRECISE_CALL_STATE_NOT_VALID;
+ private int mDisconnectCause = DisconnectCause.NOT_VALID;
+ private int mPreciseDisconnectCause = PreciseDisconnectCause.NOT_VALID;
+
+ /**
+ * Constructor
+ *
+ * @hide
+ */
+ public PreciseCallState(int ringingCall, int foregroundCall, int backgroundCall,
+ int disconnectCause, int preciseDisconnectCause) {
+ mRingingCallState = ringingCall;
+ mForegroundCallState = foregroundCall;
+ mBackgroundCallState = backgroundCall;
+ mDisconnectCause = disconnectCause;
+ mPreciseDisconnectCause = preciseDisconnectCause;
+ }
+
+ /**
+ * Empty Constructor
+ *
+ * @hide
+ */
+ public PreciseCallState() {
+ }
+
+ /**
+ * Construct a PreciseCallState object from the given parcel.
+ */
+ private PreciseCallState(Parcel in) {
+ mRingingCallState = in.readInt();
+ mForegroundCallState = in.readInt();
+ mBackgroundCallState = in.readInt();
+ mDisconnectCause = in.readInt();
+ mPreciseDisconnectCause = in.readInt();
+ }
+
+ /**
+ * Get precise ringing call state
+ *
+ * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+ * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+ * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+ * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+ * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+ * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+ * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+ */
+ public int getRingingCallState() {
+ return mRingingCallState;
+ }
+
+ /**
+ * Get precise foreground call state
+ *
+ * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+ * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+ * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+ * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+ * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+ * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+ * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+ */
+ public int getForegroundCallState() {
+ return mForegroundCallState;
+ }
+
+ /**
+ * Get precise background call state
+ *
+ * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+ * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+ * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+ * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+ * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+ * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+ * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+ */
+ public int getBackgroundCallState() {
+ return mBackgroundCallState;
+ }
+
+ /**
+ * Get disconnect cause generated by the framework
+ *
+ * @see DisconnectCause#NOT_VALID
+ * @see DisconnectCause#NOT_DISCONNECTED
+ * @see DisconnectCause#INCOMING_MISSED
+ * @see DisconnectCause#NORMAL
+ * @see DisconnectCause#LOCAL
+ * @see DisconnectCause#BUSY
+ * @see DisconnectCause#CONGESTION
+ * @see DisconnectCause#MMI
+ * @see DisconnectCause#INVALID_NUMBER
+ * @see DisconnectCause#NUMBER_UNREACHABLE
+ * @see DisconnectCause#SERVER_UNREACHABLE
+ * @see DisconnectCause#INVALID_CREDENTIALS
+ * @see DisconnectCause#OUT_OF_NETWORK
+ * @see DisconnectCause#SERVER_ERROR
+ * @see DisconnectCause#TIMED_OUT
+ * @see DisconnectCause#LOST_SIGNAL
+ * @see DisconnectCause#LIMIT_EXCEEDED
+ * @see DisconnectCause#INCOMING_REJECTED
+ * @see DisconnectCause#POWER_OFF
+ * @see DisconnectCause#OUT_OF_SERVICE
+ * @see DisconnectCause#ICC_ERROR
+ * @see DisconnectCause#CALL_BARRED
+ * @see DisconnectCause#FDN_BLOCKED
+ * @see DisconnectCause#CS_RESTRICTED
+ * @see DisconnectCause#CS_RESTRICTED_NORMAL
+ * @see DisconnectCause#CS_RESTRICTED_EMERGENCY
+ * @see DisconnectCause#UNOBTAINABLE_NUMBER
+ * @see DisconnectCause#CDMA_LOCKED_UNTIL_POWER_CYCLE
+ * @see DisconnectCause#CDMA_DROP
+ * @see DisconnectCause#CDMA_INTERCEPT
+ * @see DisconnectCause#CDMA_REORDER
+ * @see DisconnectCause#CDMA_SO_REJECT
+ * @see DisconnectCause#CDMA_RETRY_ORDER
+ * @see DisconnectCause#CDMA_ACCESS_FAILURE
+ * @see DisconnectCause#CDMA_PREEMPTED
+ * @see DisconnectCause#CDMA_NOT_EMERGENCY
+ * @see DisconnectCause#CDMA_ACCESS_BLOCKED
+ * @see DisconnectCause#ERROR_UNSPECIFIED
+ */
+ public int getDisconnectCause() {
+ return mDisconnectCause;
+ }
+
+ /**
+ * Get disconnect cause generated by the RIL
+ *
+ * @see PreciseDisconnectCause#NOT_VALID
+ * @see PreciseDisconnectCause#NO_DISCONNECT_CAUSE_AVAILABLE
+ * @see PreciseDisconnectCause#UNOBTAINABLE_NUMBER
+ * @see PreciseDisconnectCause#NORMAL
+ * @see PreciseDisconnectCause#BUSY
+ * @see PreciseDisconnectCause#NUMBER_CHANGED
+ * @see PreciseDisconnectCause#STATUS_ENQUIRY
+ * @see PreciseDisconnectCause#NORMAL_UNSPECIFIED
+ * @see PreciseDisconnectCause#NO_CIRCUIT_AVAIL
+ * @see PreciseDisconnectCause#TEMPORARY_FAILURE
+ * @see PreciseDisconnectCause#SWITCHING_CONGESTION
+ * @see PreciseDisconnectCause#CHANNEL_NOT_AVAIL
+ * @see PreciseDisconnectCause#QOS_NOT_AVAIL
+ * @see PreciseDisconnectCause#BEARER_NOT_AVAIL
+ * @see PreciseDisconnectCause#ACM_LIMIT_EXCEEDED
+ * @see PreciseDisconnectCause#CALL_BARRED
+ * @see PreciseDisconnectCause#FDN_BLOCKED
+ * @see PreciseDisconnectCause#IMSI_UNKNOWN_IN_VLR
+ * @see PreciseDisconnectCause#IMEI_NOT_ACCEPTED
+ * @see PreciseDisconnectCause#CDMA_LOCKED_UNTIL_POWER_CYCLE
+ * @see PreciseDisconnectCause#CDMA_DROP
+ * @see PreciseDisconnectCause#CDMA_INTERCEPT
+ * @see PreciseDisconnectCause#CDMA_REORDER
+ * @see PreciseDisconnectCause#CDMA_SO_REJECT
+ * @see PreciseDisconnectCause#CDMA_RETRY_ORDER
+ * @see PreciseDisconnectCause#CDMA_ACCESS_FAILURE
+ * @see PreciseDisconnectCause#CDMA_PREEMPTED
+ * @see PreciseDisconnectCause#CDMA_NOT_EMERGENCY
+ * @see PreciseDisconnectCause#CDMA_ACCESS_BLOCKED
+ * @see PreciseDisconnectCause#ERROR_UNSPECIFIED
+ */
+ public int getPreciseDisconnectCause() {
+ return mPreciseDisconnectCause;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mRingingCallState);
+ out.writeInt(mForegroundCallState);
+ out.writeInt(mBackgroundCallState);
+ out.writeInt(mDisconnectCause);
+ out.writeInt(mPreciseDisconnectCause);
+ }
+
+ public static final Parcelable.Creator<PreciseCallState> CREATOR
+ = new Parcelable.Creator<PreciseCallState>() {
+
+ public PreciseCallState createFromParcel(Parcel in) {
+ return new PreciseCallState(in);
+ }
+
+ public PreciseCallState[] newArray(int size) {
+ return new PreciseCallState[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mRingingCallState;
+ result = prime * result + mForegroundCallState;
+ result = prime * result + mBackgroundCallState;
+ result = prime * result + mDisconnectCause;
+ result = prime * result + mPreciseDisconnectCause;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PreciseCallState other = (PreciseCallState) obj;
+ return (mRingingCallState != other.mRingingCallState &&
+ mForegroundCallState != other.mForegroundCallState &&
+ mBackgroundCallState != other.mBackgroundCallState &&
+ mDisconnectCause != other.mDisconnectCause &&
+ mPreciseDisconnectCause != other.mPreciseDisconnectCause);
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ sb.append("Ringing call state: " + mRingingCallState);
+ sb.append(", Foreground call state: " + mForegroundCallState);
+ sb.append(", Background call state: " + mBackgroundCallState);
+ sb.append(", Disconnect cause: " + mDisconnectCause);
+ sb.append(", Precise disconnect cause: " + mPreciseDisconnectCause);
+
+ return sb.toString();
+ }
+}
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.aidl b/telephony/java/android/telephony/PreciseDataConnectionState.aidl
new file mode 100644
index 0000000..07ad762
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable PreciseDataConnectionState;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
new file mode 100644
index 0000000..87529fe
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -0,0 +1,275 @@
+/*
+ * 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.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.net.LinkProperties;
+
+/**
+ * Contains precise data connection state.
+ *
+ * The following data connection information is included in returned PreciseDataConnectionState:
+ *
+ * <ul>
+ * <li>Data connection state.
+ * <li>Network type of the connection.
+ * <li>APN type.
+ * <li>APN.
+ * <li>Data connection change reason.
+ * <li>The properties of the network link.
+ * <li>Data connection fail cause.
+ * </ul>
+ *
+ * @hide
+ */
+public class PreciseDataConnectionState implements Parcelable {
+
+ private int mState = TelephonyManager.DATA_UNKNOWN;
+ private int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ private String mAPNType = "";
+ private String mAPN = "";
+ private String mReason = "";
+ private LinkProperties mLinkProperties = null;
+ private String mFailCause = "";
+
+ /**
+ * Constructor
+ *
+ * @hide
+ */
+ public PreciseDataConnectionState(int state, int networkType,
+ String apnType, String apn, String reason,
+ LinkProperties linkProperties, String failCause) {
+ mState = state;
+ mNetworkType = networkType;
+ mAPNType = apnType;
+ mAPN = apn;
+ mReason = reason;
+ mLinkProperties = linkProperties;
+ mFailCause = failCause;
+ }
+
+ /**
+ * Empty Constructor
+ *
+ * @hide
+ */
+ public PreciseDataConnectionState() {
+ }
+
+ /**
+ * Construct a PreciseDataConnectionState object from the given parcel.
+ */
+ private PreciseDataConnectionState(Parcel in) {
+ mState = in.readInt();
+ mNetworkType = in.readInt();
+ mAPNType = in.readString();
+ mAPN = in.readString();
+ mReason = in.readString();
+ mLinkProperties = (LinkProperties)in.readParcelable(null);
+ mFailCause = in.readString();
+ }
+
+ /**
+ * Get data connection state
+ *
+ * @see TelephonyManager#DATA_UNKNOWN
+ * @see TelephonyManager#DATA_DISCONNECTED
+ * @see TelephonyManager#DATA_CONNECTING
+ * @see TelephonyManager#DATA_CONNECTED
+ * @see TelephonyManager#DATA_SUSPENDED
+ */
+ public int getDataConnectionState() {
+ return mState;
+ }
+
+ /**
+ * Get data connection network type
+ *
+ * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+ * @see TelephonyManager#NETWORK_TYPE_GPRS
+ * @see TelephonyManager#NETWORK_TYPE_EDGE
+ * @see TelephonyManager#NETWORK_TYPE_UMTS
+ * @see TelephonyManager#NETWORK_TYPE_CDMA
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+ * @see TelephonyManager#NETWORK_TYPE_1xRTT
+ * @see TelephonyManager#NETWORK_TYPE_HSDPA
+ * @see TelephonyManager#NETWORK_TYPE_HSUPA
+ * @see TelephonyManager#NETWORK_TYPE_HSPA
+ * @see TelephonyManager#NETWORK_TYPE_IDEN
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+ * @see TelephonyManager#NETWORK_TYPE_LTE
+ * @see TelephonyManager#NETWORK_TYPE_EHRPD
+ * @see TelephonyManager#NETWORK_TYPE_HSPAP
+ */
+ public int getDataConnectionNetworkType() {
+ return mNetworkType;
+ }
+
+ /**
+ * Get data connection APN type
+ */
+ public String getDataConnectionAPNType() {
+ return mAPNType;
+ }
+
+ /**
+ * Get data connection APN.
+ */
+ public String getDataConnectionAPN() {
+ return mAPN;
+ }
+
+ /**
+ * Get data connection change reason.
+ */
+ public String getDataConnectionChangeReason() {
+ return mReason;
+ }
+
+ /**
+ * Get the properties of the network link.
+ */
+ public LinkProperties getDataConnectionLinkProperties() {
+ return mLinkProperties;
+ }
+
+ /**
+ * Get data connection fail cause, in case there was a failure.
+ */
+ public String getDataConnectionFailCause() {
+ return mFailCause;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mState);
+ out.writeInt(mNetworkType);
+ out.writeString(mAPNType);
+ out.writeString(mAPN);
+ out.writeString(mReason);
+ out.writeParcelable(mLinkProperties, flags);
+ out.writeString(mFailCause);
+ }
+
+ public static final Parcelable.Creator<PreciseDataConnectionState> CREATOR
+ = new Parcelable.Creator<PreciseDataConnectionState>() {
+
+ public PreciseDataConnectionState createFromParcel(Parcel in) {
+ return new PreciseDataConnectionState(in);
+ }
+
+ public PreciseDataConnectionState[] newArray(int size) {
+ return new PreciseDataConnectionState[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mState;
+ result = prime * result + mNetworkType;
+ result = prime * result + ((mAPNType == null) ? 0 : mAPNType.hashCode());
+ result = prime * result + ((mAPN == null) ? 0 : mAPN.hashCode());
+ result = prime * result + ((mReason == null) ? 0 : mReason.hashCode());
+ result = prime * result + ((mLinkProperties == null) ? 0 : mLinkProperties.hashCode());
+ result = prime * result + ((mFailCause == null) ? 0 : mFailCause.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ PreciseDataConnectionState other = (PreciseDataConnectionState) obj;
+ if (mAPN == null) {
+ if (other.mAPN != null) {
+ return false;
+ }
+ } else if (!mAPN.equals(other.mAPN)) {
+ return false;
+ }
+ if (mAPNType == null) {
+ if (other.mAPNType != null) {
+ return false;
+ }
+ } else if (!mAPNType.equals(other.mAPNType)) {
+ return false;
+ }
+ if (mFailCause == null) {
+ if (other.mFailCause != null) {
+ return false;
+ }
+ } else if (!mFailCause.equals(other.mFailCause)) {
+ return false;
+ }
+ if (mLinkProperties == null) {
+ if (other.mLinkProperties != null) {
+ return false;
+ }
+ } else if (!mLinkProperties.equals(other.mLinkProperties)) {
+ return false;
+ }
+ if (mNetworkType != other.mNetworkType) {
+ return false;
+ }
+ if (mReason == null) {
+ if (other.mReason != null) {
+ return false;
+ }
+ } else if (!mReason.equals(other.mReason)) {
+ return false;
+ }
+ if (mState != other.mState) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("Data Connection state: " + mState);
+ sb.append(", Network type: " + mNetworkType);
+ sb.append(", APN type: " + mAPNType);
+ sb.append(", APN: " + mAPN);
+ sb.append(", Change reason: " + mReason);
+ sb.append(", Link properties: " + mLinkProperties);
+ sb.append(", Fail cause: " + mFailCause);
+
+ return sb.toString();
+ }
+}
diff --git a/telephony/java/android/telephony/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
new file mode 100644
index 0000000..54ab19d
--- /dev/null
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+/**
+ * Contains precise disconnect call causes generated by the
+ * framework and the RIL.
+ *
+ * @hide
+ */
+public class PreciseDisconnectCause {
+
+ /** The disconnect cause is not valid (Not received a disconnect cause)*/
+ public static final int NOT_VALID = -1;
+ /** No disconnect cause provided. Generally a local disconnect or an incoming missed call */
+ public static final int NO_DISCONNECT_CAUSE_AVAILABLE = 0;
+ /**
+ * The destination cannot be reached because the number, although valid,
+ * is not currently assigned
+ */
+ public static final int UNOBTAINABLE_NUMBER = 1;
+ /** One of the users involved in the call has requested that the call is cleared */
+ public static final int NORMAL = 16;
+ /** The called user is unable to accept another call */
+ public static final int BUSY = 17;
+ /** The called number is no longer assigned */
+ public static final int NUMBER_CHANGED = 22;
+ /** Provided in response to a STATUS ENQUIRY message */
+ public static final int STATUS_ENQUIRY = 30;
+ /** Reports a normal disconnect only when no other normal cause applies */
+ public static final int NORMAL_UNSPECIFIED = 31;
+ /** There is no channel presently available to handle the call */
+ public static final int NO_CIRCUIT_AVAIL = 34;
+ /**
+ * The network is not functioning correctly and the condition is not likely to last
+ * a long period of time
+ */
+ public static final int TEMPORARY_FAILURE = 41;
+ /** The switching equipment is experiencing a period of high traffic */
+ public static final int SWITCHING_CONGESTION = 42;
+ /** The channel cannot be provided */
+ public static final int CHANNEL_NOT_AVAIL = 44;
+ /** The requested quality of service (ITU-T X.213) cannot be provided */
+ public static final int QOS_NOT_AVAIL = 49;
+ /** The requested bearer capability is not available at this time */
+ public static final int BEARER_NOT_AVAIL = 58;
+ /** The call clearing is due to ACM being greater than or equal to ACMmax */
+ public static final int ACM_LIMIT_EXCEEDED = 68;
+ /** The call is restricted */
+ public static final int CALL_BARRED = 240;
+ /** The call is blocked by the Fixed Dialing Number list */
+ public static final int FDN_BLOCKED = 241;
+ /** The given IMSI is not known at the VLR */
+ /** TS 24.008 cause 4 */
+ public static final int IMSI_UNKNOWN_IN_VLR = 242;
+ /**
+ * The network does not accept emergency call establishment using an IMEI or not accept attach
+ * procedure for emergency services using an IMEI
+ */
+ public static final int IMEI_NOT_ACCEPTED = 243;
+ /** MS is locked until next power cycle */
+ public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000;
+ /** Drop call*/
+ public static final int CDMA_DROP = 1001;
+ /** INTERCEPT order received, MS state idle entered */
+ public static final int CDMA_INTERCEPT = 1002;
+ /** MS has been redirected, call is cancelled */
+ public static final int CDMA_REORDER = 1003;
+ /** Service option rejection */
+ public static final int CDMA_SO_REJECT = 1004;
+ /** Requested service is rejected, retry delay is set */
+ public static final int CDMA_RETRY_ORDER = 1005;
+ /** Unable to obtain access to the CDMA system */
+ public static final int CDMA_ACCESS_FAILURE = 1006;
+ /** Not a preempted call */
+ public static final int CDMA_PREEMPTED = 1007;
+ /** Not an emergency call */
+ public static final int CDMA_NOT_EMERGENCY = 1008;
+ /** Access Blocked by CDMA network */
+ public static final int CDMA_ACCESS_BLOCKED = 1009;
+ /** Disconnected due to unspecified reasons */
+ public static final int ERROR_UNSPECIFIED = 0xffff;
+
+ /** Private constructor to avoid class instantiation. */
+ private PreciseDisconnectCause() {
+ // Do nothing.
+ }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3d416fb..d28d76d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -210,6 +210,267 @@
*/
public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
+ /**
+ * Broadcast intent action indicating that a precise call state
+ * (cellular) on the device has changed.
+ *
+ * <p>
+ * The {@link #EXTRA_RINGING_CALL_STATE} extra indicates the ringing call state.
+ * The {@link #EXTRA_FOREGROUND_CALL_STATE} extra indicates the foreground call state.
+ * The {@link #EXTRA_BACKGROUND_CALL_STATE} extra indicates the background call state.
+ * The {@link #EXTRA_DISCONNECT_CAUSE} extra indicates the disconnect cause.
+ * The {@link #EXTRA_PRECISE_DISCONNECT_CAUSE} extra indicates the precise disconnect cause.
+ *
+ * <p class="note">
+ * Requires the READ_PRECISE_PHONE_STATE permission.
+ *
+ * @see #EXTRA_RINGING_CALL_STATE
+ * @see #EXTRA_FOREGROUND_CALL_STATE
+ * @see #EXTRA_BACKGROUND_CALL_STATE
+ * @see #EXTRA_DISCONNECT_CAUSE
+ * @see #EXTRA_PRECISE_DISCONNECT_CAUSE
+ *
+ * <p class="note">
+ * Requires the READ_PRECISE_PHONE_STATE permission.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PRECISE_CALL_STATE_CHANGED =
+ "android.intent.action.PRECISE_CALL_STATE";
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+ * for an integer containing the state of the current ringing call.
+ *
+ * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+ * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+ * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+ * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+ * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+ * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+ * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_RINGING_CALL_STATE = "ringing_state";
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+ * for an integer containing the state of the current foreground call.
+ *
+ * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+ * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+ * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+ * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+ * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+ * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+ * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_FOREGROUND_CALL_STATE = "foreground_state";
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+ * for an integer containing the state of the current background call.
+ *
+ * @see PreciseCallState#PRECISE_CALL_STATE_NOT_VALID
+ * @see PreciseCallState#PRECISE_CALL_STATE_IDLE
+ * @see PreciseCallState#PRECISE_CALL_STATE_ACTIVE
+ * @see PreciseCallState#PRECISE_CALL_STATE_HOLDING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DIALING
+ * @see PreciseCallState#PRECISE_CALL_STATE_ALERTING
+ * @see PreciseCallState#PRECISE_CALL_STATE_INCOMING
+ * @see PreciseCallState#PRECISE_CALL_STATE_WAITING
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTED
+ * @see PreciseCallState#PRECISE_CALL_STATE_DISCONNECTING
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_BACKGROUND_CALL_STATE = "background_state";
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+ * for an integer containing the disconnect cause.
+ *
+ * @see DisconnectCause
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DISCONNECT_CAUSE = "disconnect_cause";
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_CALL_STATE_CHANGED} broadcast
+ * for an integer containing the disconnect cause provided by the RIL.
+ *
+ * @see PreciseDisconnectCause
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause";
+
+ /**
+ * Broadcast intent action indicating a data connection has changed,
+ * providing precise information about the connection.
+ *
+ * <p>
+ * The {@link #EXTRA_DATA_STATE} extra indicates the connection state.
+ * The {@link #EXTRA_DATA_NETWORK_TYPE} extra indicates the connection network type.
+ * The {@link #EXTRA_DATA_APN_TYPE} extra indicates the APN type.
+ * The {@link #EXTRA_DATA_APN} extra indicates the APN.
+ * The {@link #EXTRA_DATA_CHANGE_REASON} extra indicates the connection change reason.
+ * The {@link #EXTRA_DATA_IFACE_PROPERTIES} extra indicates the connection interface.
+ * The {@link #EXTRA_DATA_FAILURE_CAUSE} extra indicates the connection fail cause.
+ *
+ * <p class="note">
+ * Requires the READ_PRECISE_PHONE_STATE permission.
+ *
+ * @see #EXTRA_DATA_STATE
+ * @see #EXTRA_DATA_NETWORK_TYPE
+ * @see #EXTRA_DATA_APN_TYPE
+ * @see #EXTRA_DATA_APN
+ * @see #EXTRA_DATA_CHANGE_REASON
+ * @see #EXTRA_DATA_IFACE
+ * @see #EXTRA_DATA_FAILURE_CAUSE
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED =
+ "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for an integer containing the state of the current data connection.
+ *
+ * @see TelephonyManager#DATA_UNKNOWN
+ * @see TelephonyManager#DATA_DISCONNECTED
+ * @see TelephonyManager#DATA_CONNECTING
+ * @see TelephonyManager#DATA_CONNECTED
+ * @see TelephonyManager#DATA_SUSPENDED
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_STATE = PhoneConstants.STATE_KEY;
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for an integer containing the network type.
+ *
+ * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+ * @see TelephonyManager#NETWORK_TYPE_GPRS
+ * @see TelephonyManager#NETWORK_TYPE_EDGE
+ * @see TelephonyManager#NETWORK_TYPE_UMTS
+ * @see TelephonyManager#NETWORK_TYPE_CDMA
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+ * @see TelephonyManager#NETWORK_TYPE_1xRTT
+ * @see TelephonyManager#NETWORK_TYPE_HSDPA
+ * @see TelephonyManager#NETWORK_TYPE_HSUPA
+ * @see TelephonyManager#NETWORK_TYPE_HSPA
+ * @see TelephonyManager#NETWORK_TYPE_IDEN
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+ * @see TelephonyManager#NETWORK_TYPE_LTE
+ * @see TelephonyManager#NETWORK_TYPE_EHRPD
+ * @see TelephonyManager#NETWORK_TYPE_HSPAP
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getIntExtra(String name, int defaultValue)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_NETWORK_TYPE = PhoneConstants.DATA_NETWORK_TYPE_KEY;
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for an String containing the data APN type.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getStringExtra(String name)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY;
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for an String containing the data APN.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getStringExtra(String name)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY;
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for an String representation of the change reason.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getStringExtra(String name)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_CHANGE_REASON = PhoneConstants.STATE_CHANGE_REASON_KEY;
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for an String representation of the data interface.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getParcelableExtra(String name)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_LINK_PROPERTIES_KEY = PhoneConstants.DATA_LINK_PROPERTIES_KEY;
+
+ /**
+ * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast
+ * for the data connection fail cause.
+ *
+ * <p class="note">
+ * Retrieve with
+ * {@link android.content.Intent#getStringExtra(String name)}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
//
//
@@ -1562,10 +1823,11 @@
}
/**
- * Perform the specified type of NV config reset.
- * Used for device configuration by some CDMA operators.
+ * Perform the specified type of NV config reset. The radio will be taken offline
+ * and the device must be rebooted after the operation. Used for device
+ * configuration by some CDMA operators.
*
- * @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
+ * @param resetType reset type: 1: reload NV reset, 2: erase NV reset, 3: factory NV reset
* @return true on success; false on any failure.
* @hide
*/
@@ -1579,24 +1841,4 @@
}
return false;
}
-
- /**
- * Change the radio to the specified mode.
- * Used for device configuration by some operators.
- *
- * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
- * or 3 to reset the radio.
- * @return true on success; false on any failure.
- * @hide
- */
- public boolean setRadioMode(int radioMode) {
- try {
- return getITelephony().setRadioMode(radioMode);
- } catch (RemoteException ex) {
- Rlog.e(TAG, "setRadioMode RemoteException", ex);
- } catch (NullPointerException ex) {
- Rlog.e(TAG, "setRadioMode NPE", ex);
- }
- return false;
- }
}
diff --git a/telephony/java/android/telephony/ThirdPartyCallListener.java b/telephony/java/android/telephony/ThirdPartyCallListener.java
deleted file mode 100644
index 00265f8..0000000
--- a/telephony/java/android/telephony/ThirdPartyCallListener.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2013 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.telephony;
-
-import android.os.RemoteException;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface provided to {@link android.telephony.ThirdPartyCallService}. The service can use this
- * to notify the listener of changes to the call state.
- */
-public class ThirdPartyCallListener {
- private final IThirdPartyCallListener mListener;
-
- // Call end reason. TODO: rename this to DisconnectCause once they are public.
- public static final int CALL_END_NORMAL = 1;
- public static final int CALL_END_INCOMING_MISSED = 2;
- public static final int CALL_END_OTHER = 3;
-
- public ThirdPartyCallListener(IThirdPartyCallListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException("Invalid listener");
- }
- mListener = listener;
- }
-
- /**
- * Called by the service when a call provider is available to perform the outgoing or incoming
- * call.
- */
- public void onCallProviderAttached(ThirdPartyCallProvider callProvider) {
- try {
- mListener.onCallProviderAttached(callProvider.getCallback());
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Notifies the listener that ringing has started for this call.
- */
- public void onRingingStarted() {
- try {
- mListener.onRingingStarted();
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Notifies the listener that the call has been successfully established.
- */
- public void onCallEstablished() {
- try {
- mListener.onCallEstablished();
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Notifies the listener that the call has ended.
- */
- public void onCallEnded(int reason) {
- try {
- mListener.onCallEnded(reason);
- } catch (RemoteException e) {
- }
- }
-}
diff --git a/telephony/java/android/telephony/ThirdPartyCallProvider.java b/telephony/java/android/telephony/ThirdPartyCallProvider.java
deleted file mode 100644
index bd8a1ea..0000000
--- a/telephony/java/android/telephony/ThirdPartyCallProvider.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2013 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.telephony;
-
-import android.os.Handler;
-import android.os.Message;
-
-import com.android.internal.telephony.IThirdPartyCallProvider;
-
-/**
- * Interface sent to {@link android.telephony.ThirdPartyCallListener#onCallProviderAttached
- * onCallProviderAttached}. This is used to control an outgoing or an incoming call.
- */
-public class ThirdPartyCallProvider {
- private static final int MSG_MUTE = 1;
- private static final int MSG_HANGUP = 2;
- private static final int MSG_INCOMING_CALL_ACCEPT = 3;
- private static final int MSG_SEND_DTMF = 4;
-
- /**
- * Mutes or unmutes the call.
- */
- public void mute(boolean shouldMute) {
- // default implementation empty
- }
-
- /**
- * Ends the current call. If this is an unanswered incoming call then the call is rejected.
- */
- public void hangup() {
- // default implementation empty
- }
-
- /**
- * Accepts the incoming call.
- */
- public void incomingCallAccept() {
- // default implementation empty
- }
-
- /**
- * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
- */
- public void sendDtmf(char c) {
- // default implementation empty
- }
-
- IThirdPartyCallProvider getCallback() {
- return mCallback;
- }
-
- private final IThirdPartyCallProvider mCallback = new IThirdPartyCallProvider.Stub() {
- @Override
- public void mute(boolean shouldMute) {
- Message.obtain(mHandler, MSG_MUTE, shouldMute ? 1 : 0, 0).sendToTarget();
- }
-
- @Override
- public void hangup() {
- Message.obtain(mHandler, MSG_HANGUP).sendToTarget();
- }
-
- @Override
- public void incomingCallAccept() {
- Message.obtain(mHandler, MSG_INCOMING_CALL_ACCEPT).sendToTarget();
- }
-
- @Override
- public void sendDtmf(char c) {
- Message.obtain(mHandler, MSG_SEND_DTMF, (int) c, 0).sendToTarget();
- }
- };
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_MUTE:
- mute(msg.arg1 != 0);
- break;
- case MSG_HANGUP:
- hangup();
- break;
- case MSG_INCOMING_CALL_ACCEPT:
- incomingCallAccept();
- break;
- case MSG_SEND_DTMF:
- sendDtmf((char) msg.arg1);
- break;
- }
- }
- };
-}
diff --git a/telephony/java/android/telephony/ThirdPartyCallService.java b/telephony/java/android/telephony/ThirdPartyCallService.java
deleted file mode 100644
index 6eddb43..0000000
--- a/telephony/java/android/telephony/ThirdPartyCallService.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2013 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.telephony;
-
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.util.Pair;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-import com.android.internal.telephony.IThirdPartyCallService;
-
-/**
- * Interface provided by a service to start outgoing calls and attach to incoming calls.
- */
-public class ThirdPartyCallService {
- private static final int MSG_OUTGOING_CALL_INITIATE = 1;
- private static final int MSG_INCOMING_CALL_ATTACH = 2;
-
- /**
- * Call to start a new outgoing call.
- */
- public void outgoingCallInitiate(ThirdPartyCallListener listener, String number) {
- // default implementation empty
- }
-
- /**
- * Call to attach to an incoming call.
- */
- public void incomingCallAttach(ThirdPartyCallListener listener, String callId) {
- // default implementation empty
- }
-
- /**
- * Returns an IBinder instance that can returned from the service's onBind function.
- */
- public IBinder getBinder() {
- return mCallback;
- }
-
- private final IThirdPartyCallService.Stub mCallback = new IThirdPartyCallService.Stub() {
- @Override
- public void outgoingCallInitiate(IThirdPartyCallListener listener, String number) {
- Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.IThirdPartyCallService.out");
- Message.obtain(mHandler, MSG_OUTGOING_CALL_INITIATE,
- Pair.create(listener, number)).sendToTarget();
- }
-
- @Override
- public void incomingCallAttach(IThirdPartyCallListener listener, String callId) {
- Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.IThirdPartyCallService.in");
- Message.obtain(mHandler, MSG_INCOMING_CALL_ATTACH,
- Pair.create(listener, callId)).sendToTarget();
- }
- };
-
- private final Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage: " + msg.what);
- switch (msg.what) {
- case MSG_OUTGOING_CALL_INITIATE: {
- Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage out");
- Pair<IThirdPartyCallListener, String> pair =
- (Pair<IThirdPartyCallListener, String>) msg.obj;
- ThirdPartyCallListener listener = new ThirdPartyCallListener(pair.first);
- outgoingCallInitiate(listener, pair.second);
- break;
- }
- case MSG_INCOMING_CALL_ATTACH: {
- Rlog.w("ThirdPartyPhone", "ThirdPartyCallService.handleMessage in");
- Pair<IThirdPartyCallListener, String> pair =
- (Pair<IThirdPartyCallListener, String>) msg.obj;
- ThirdPartyCallListener listener = new ThirdPartyCallListener(pair.first);
- incomingCallAttach(listener, pair.second);
- break;
- }
- }
- }
- };
-}
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 4be11b8..59bdf64 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -97,6 +97,7 @@
public static final int CMD_ENABLE_MOBILE_PROVISIONING = BASE + 37;
public static final int CMD_IS_PROVISIONING_APN = BASE + 38;
public static final int EVENT_PROVISIONING_APN_ALARM = BASE + 39;
+ public static final int CMD_NET_STAT_POLL = BASE + 40;
/***** Constants *****/
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 3a04ceb..f228d4e 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -20,6 +20,8 @@
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
+import android.telephony.PreciseCallState;
+import android.telephony.PreciseDataConnectionState;
oneway interface IPhoneStateListener {
void onServiceStateChanged(in ServiceState serviceState);
@@ -35,5 +37,7 @@
void onSignalStrengthsChanged(in SignalStrength signalStrength);
void onOtaspChanged(in int otaspMode);
void onCellInfoChanged(in List<CellInfo> cellInfo);
+ void onPreciseCallStateChanged(in PreciseCallState callState);
+ void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 370e27a..554a9cb 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -395,21 +395,12 @@
boolean nvWriteCdmaPrl(in byte[] preferredRoamingList);
/**
- * Perform the specified type of NV config reset.
- * Used for device configuration by some CDMA operators.
+ * Perform the specified type of NV config reset. The radio will be taken offline
+ * and the device must be rebooted after the operation. Used for device
+ * configuration by some CDMA operators.
*
* @param resetType the type of reset to perform (1 == factory reset; 2 == NV-only reset).
* @return true on success; false on any failure.
*/
boolean nvResetConfig(int resetType);
-
- /**
- * Change the radio to the specified mode.
- * Used for device configuration by some operators.
- *
- * @param radioMode is 0 for offline mode, 1 for online mode, 2 for low-power mode,
- * or 3 to reset the radio.
- * @return true on success; false on any failure.
- */
- boolean setRadioMode(int radioMode);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 59c8472..546ce17 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -41,4 +41,9 @@
void notifyCellLocation(in Bundle cellLocation);
void notifyOtaspChanged(in int otaspMode);
void notifyCellInfo(in List<CellInfo> cellInfo);
+ void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
+ int backgroundCallState);
+ void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause);
+ void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
+ String failCause);
}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
deleted file mode 100644
index bcf2d81..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallListener.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2013 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.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallProvider;
-
-/**
- * Interface provided to ThirdPartyCallService. The service can use this to notify the listener of
- * changes to the call state.
- */
-oneway interface IThirdPartyCallListener {
- /**
- * Called by the service when a call provider is available to perform the outgoing or incoming
- * call.
- */
- void onCallProviderAttached(IThirdPartyCallProvider callProvider);
-
- /**
- * Notifies the listener that ringing has started for this call.
- */
- void onRingingStarted();
-
- /**
- * Notifies the listener that the call has been successfully established.
- */
- void onCallEstablished();
-
- /**
- * Notifies the listener that the call has ended.
- */
- void onCallEnded(int reason);
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
deleted file mode 100644
index a9d67a4..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallProvider.aidl
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2013 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.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface sent to ThirdPartyCallListener.onCallProviderAttached. This is used to control an
- * outgoing or incoming call.
- */
-oneway interface IThirdPartyCallProvider {
- /**
- * Mutes or unmutes the call.
- */
- void mute(boolean shouldMute);
-
- /**
- * Ends the current call. If this is an unanswered incoming call then the call is rejected (for
- * example, a notification is sent to a server that the user declined the call).
- */
- void hangup();
-
- /**
- * Accepts the incoming call.
- */
- void incomingCallAccept();
-
- /**
- * Sends the given DTMF code. The code can be '0'-'9', 'A'-'D', '#', or '*'.
- */
- void sendDtmf(char c);
-}
diff --git a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl b/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
deleted file mode 100644
index c9ee4ed..0000000
--- a/telephony/java/com/android/internal/telephony/IThirdPartyCallService.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2013 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.telephony;
-
-import com.android.internal.telephony.IThirdPartyCallListener;
-
-/**
- * Interface provided by a service to start outgoing calls and attach to incoming calls.
- */
-oneway interface IThirdPartyCallService {
- /**
- * Call to start a new outgoing call.
- */
- void outgoingCallInitiate(IThirdPartyCallListener listener, String number);
-
- /**
- * Call to attach to an incoming call.
- */
- void incomingCallAttach(IThirdPartyCallListener listener, String callId);
-}
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index fc6c997..8c42d25 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -73,6 +73,8 @@
public static final String PHONE_NAME_KEY = "phoneName";
public static final String FAILURE_REASON_KEY = "reason";
public static final String STATE_CHANGE_REASON_KEY = "reason";
+ public static final String DATA_NETWORK_TYPE_KEY = "networkType";
+ public static final String DATA_FAILURE_CAUSE_KEY = "failCause";
public static final String DATA_APN_TYPE_KEY = "apnType";
public static final String DATA_APN_KEY = "apn";
public static final String DATA_LINK_PROPERTIES_KEY = "linkProperties";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 6015df0..d338857 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -115,8 +115,9 @@
int DEACTIVATE_REASON_PDP_RESET = 2;
/* NV config radio reset types. */
- int NV_CONFIG_RESET_FACTORY = 1;
- int NV_CONFIG_RESET_NV_ONLY = 2;
+ int NV_CONFIG_RELOAD_RESET = 1;
+ int NV_CONFIG_ERASE_RESET = 2;
+ int NV_CONFIG_FACTORY_RESET = 3;
/*
cat include/telephony/ril.h | \
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 62f6aff..dfb8070 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -85,11 +85,13 @@
// do initial app launch, without force stopping
for (String app : mNameToResultKey.keySet()) {
long launchTime = startApp(app, false);
- if (launchTime <=0 ) {
+ if (launchTime <= 0) {
mNameToLaunchTime.put(app, -1L);
// simply pass the app if launch isn't successful
// error should have already been logged by startApp
continue;
+ } else {
+ mNameToLaunchTime.put(app, launchTime);
}
sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
closeApp(app, false);
@@ -98,9 +100,9 @@
// do the real app launch now
for (int i = 0; i < mLaunchIterations; i++) {
for (String app : mNameToResultKey.keySet()) {
- long totalLaunchTime = mNameToLaunchTime.get(app);
+ long prevLaunchTime = mNameToLaunchTime.get(app);
long launchTime = 0;
- if (totalLaunchTime < 0) {
+ if (prevLaunchTime < 0) {
// skip if the app has previous failures
continue;
}
@@ -110,18 +112,19 @@
mNameToLaunchTime.put(app, -1L);
continue;
}
- totalLaunchTime += launchTime;
- mNameToLaunchTime.put(app, totalLaunchTime);
+ // keep the min launch time
+ if (launchTime < prevLaunchTime) {
+ mNameToLaunchTime.put(app, launchTime);
+ }
sleep(POST_LAUNCH_IDLE_TIMEOUT);
closeApp(app, true);
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
}
for (String app : mNameToResultKey.keySet()) {
- long totalLaunchTime = mNameToLaunchTime.get(app);
- if (totalLaunchTime != -1) {
- mResult.putDouble(mNameToResultKey.get(app),
- ((double) totalLaunchTime) / mLaunchIterations);
+ long launchTime = mNameToLaunchTime.get(app);
+ if (launchTime != -1) {
+ mResult.putLong(mNameToResultKey.get(app), launchTime);
}
}
instrumentation.sendStatus(0, mResult);
diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk
new file mode 100644
index 0000000..01f10e5
--- /dev/null
+++ b/tests/DozeTest/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := DozeTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/DozeTest/AndroidManifest.xml b/tests/DozeTest/AndroidManifest.xml
new file mode 100644
index 0000000..c199f69
--- /dev/null
+++ b/tests/DozeTest/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.dreams.dozetest">
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application android:label="@string/app_name">
+ <service
+ android:name="DozeTestDream"
+ android:exported="true"
+ android:icon="@drawable/ic_app"
+ android:label="@string/doze_dream_name">
+ <!-- Commented out to prevent this dream from appearing in the list of
+ dreams that the user can select via the Settings application.
+ <intent-filter>
+ <action android:name="android.service.dreams.DreamService" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ -->
+ </service>
+ </application>
+</manifest>
diff --git a/tests/DozeTest/res/drawable-hdpi/ic_app.png b/tests/DozeTest/res/drawable-hdpi/ic_app.png
new file mode 100755
index 0000000..66a1984
--- /dev/null
+++ b/tests/DozeTest/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/drawable-mdpi/ic_app.png b/tests/DozeTest/res/drawable-mdpi/ic_app.png
new file mode 100644
index 0000000..5ae7701
--- /dev/null
+++ b/tests/DozeTest/res/drawable-mdpi/ic_app.png
Binary files differ
diff --git a/tests/DozeTest/res/layout/dream.xml b/tests/DozeTest/res/layout/dream.xml
new file mode 100644
index 0000000..1c8fd3f
--- /dev/null
+++ b/tests/DozeTest/res/layout/dream.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/alarm_clock_label" />
+ <TextView android:id="@+id/alarm_clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <Space
+ android:layout_width="match_parent"
+ android:layout_height="32dp" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/tick_clock_label" />
+ <TextClock android:id="@+id/tick_clock"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/DozeTest/res/values/strings.xml b/tests/DozeTest/res/values/strings.xml
new file mode 100644
index 0000000..f21911f
--- /dev/null
+++ b/tests/DozeTest/res/values/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <!-- Name of the package of basic screensavers, shown in Settings > Apps. [CHAR LIMIT=40] -->
+ <string name="app_name">Doze Test</string>
+
+ <!-- Name of the screensaver. [CHAR LIMIT=40] -->
+ <string name="doze_dream_name">Doze Test</string>
+
+ <string name="alarm_clock_label">This clock is updated using the Alarm Manager</string>
+ <string name="tick_clock_label">This clock is updated using TIME_TICK Broadcasts</string>
+</resources>
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
new file mode 100644
index 0000000..bf35db4
--- /dev/null
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -0,0 +1,165 @@
+/*
+ * 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.dreams.dozetest;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PowerManager;
+import android.service.dreams.DozeHardware;
+import android.service.dreams.DreamService;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.widget.TextView;
+
+import java.util.Date;
+
+/**
+ * Simple test for doze mode.
+ * <p>
+ * adb shell setprop debug.doze.component com.android.dreams.dozetest/.DozeTestDream
+ * </p>
+ */
+public class DozeTestDream extends DreamService {
+ private static final String TAG = DozeTestDream.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ // Amount of time to allow to update the time shown on the screen before releasing
+ // the wakelock. This timeout is design to compensate for the fact that we don't
+ // currently have a way to know when time display contents have actually been
+ // refreshed once the dream has finished rendering a new frame.
+ private static final int UPDATE_TIME_TIMEOUT = 100;
+
+ // A doze hardware message string we use for end-to-end testing.
+ // Doesn't mean anything. Real hardware won't handle it.
+ private static final String TEST_PING_MESSAGE = "test.ping";
+
+ private PowerManager mPowerManager;
+ private PowerManager.WakeLock mWakeLock;
+ private AlarmManager mAlarmManager;
+ private PendingIntent mAlarmIntent;
+
+ private TextView mAlarmClock;
+
+ private final Date mTime = new Date();
+ private java.text.DateFormat mTimeFormat;
+
+ private boolean mDreaming;
+ private DozeHardware mDozeHardware;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+ mAlarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
+
+ Intent intent = new Intent("com.android.dreams.dozetest.ACTION_ALARM");
+ intent.setPackage(getPackageName());
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(intent.getAction());
+ registerReceiver(mAlarmReceiver, filter);
+ mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ unregisterReceiver(mAlarmReceiver);
+ mAlarmIntent.cancel();
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setInteractive(false);
+ setLowProfile(true);
+ setFullscreen(true);
+ setContentView(R.layout.dream);
+
+ mAlarmClock = (TextView)findViewById(R.id.alarm_clock);
+
+ mTimeFormat = DateFormat.getTimeFormat(this);
+ }
+
+ @Override
+ public void onDreamingStarted() {
+ super.onDreamingStarted();
+
+ mDreaming = true;
+ mDozeHardware = getDozeHardware();
+
+ Log.d(TAG, "Dream started: canDoze=" + canDoze()
+ + ", dozeHardware=" + mDozeHardware);
+
+ performTimeUpdate();
+
+ if (mDozeHardware != null) {
+ mDozeHardware.sendMessage(TEST_PING_MESSAGE, null);
+ mDozeHardware.setEnableMcu(true);
+ }
+ startDozing();
+ }
+
+ @Override
+ public void onDreamingStopped() {
+ super.onDreamingStopped();
+
+ mDreaming = false;
+ if (mDozeHardware != null) {
+ mDozeHardware.setEnableMcu(false);
+ mDozeHardware = null;
+ }
+
+ Log.d(TAG, "Dream ended: isDozing=" + isDozing());
+
+ stopDozing();
+ cancelTimeUpdate();
+ }
+
+ private void performTimeUpdate() {
+ if (mDreaming) {
+ long now = System.currentTimeMillis();
+ now -= now % 60000; // back up to last minute boundary
+
+ mTime.setTime(now);
+ mAlarmClock.setText(mTimeFormat.format(mTime));
+
+ mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, now + 60000, mAlarmIntent);
+
+ mWakeLock.acquire(UPDATE_TIME_TIMEOUT);
+ }
+ }
+
+ private void cancelTimeUpdate() {
+ mAlarmManager.cancel(mAlarmIntent);
+ }
+
+ private final BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ performTimeUpdate();
+ }
+ };
+}
diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk
new file mode 100644
index 0000000..93b9c9a
--- /dev/null
+++ b/tests/OneMedia/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files) \
+ $(call all-Iaidl-files-under, src)
+
+LOCAL_PACKAGE_NAME := OneMedia
+LOCAL_CERTIFICATE := platform
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-v7-appcompat \
+ android-support-v7-mediarouter
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+include $(BUILD_PACKAGE)
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
new file mode 100644
index 0000000..7d6ba1d
--- /dev/null
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.onemedia"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="19"/>
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name="com.android.onemedia.OnePlayerActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <service
+ android:name="com.android.onemedia.OnePlayerService"
+ android:exported="false"
+ android:process="com.android.onemedia.service" />
+ </application>
+
+</manifest>
diff --git a/tests/OneMedia/res/drawable-hdpi/ic_launcher.png b/tests/OneMedia/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..288b665
--- /dev/null
+++ b/tests/OneMedia/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/tests/OneMedia/res/drawable-mdpi/ic_launcher.png b/tests/OneMedia/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..6ae570b4
--- /dev/null
+++ b/tests/OneMedia/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/tests/OneMedia/res/drawable-xhdpi/ic_launcher.png b/tests/OneMedia/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..d4fb7cd
--- /dev/null
+++ b/tests/OneMedia/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/OneMedia/res/drawable-xxhdpi/ic_launcher.png b/tests/OneMedia/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..85a6081
--- /dev/null
+++ b/tests/OneMedia/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/tests/OneMedia/res/layout/activity_main.xml b/tests/OneMedia/res/layout/activity_main.xml
new file mode 100644
index 0000000..168c9b8ce
--- /dev/null
+++ b/tests/OneMedia/res/layout/activity_main.xml
@@ -0,0 +1,16 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ tools:context=".MainActivity" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hello_world" />
+
+</RelativeLayout>
diff --git a/tests/OneMedia/res/layout/activity_one_player.xml b/tests/OneMedia/res/layout/activity_one_player.xml
new file mode 100644
index 0000000..4208355
--- /dev/null
+++ b/tests/OneMedia/res/layout/activity_one_player.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2014 Google Inc. All Rights Reserved. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:text="@string/app_name"
+ style="@style/Title" />
+ <EditText
+ android:id="@+id/content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textUri"
+ android:hint="@string/media_content_hint"
+ android:gravity="center"
+ android:textSize="24sp" />
+ <EditText
+ android:id="@+id/next_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textNoSuggestions"
+ android:hint="@string/media_next_hint"
+ android:gravity="center"
+ android:textSize="24sp" />
+ <CheckBox
+ android:id="@+id/has_video"
+ android:layout_marginRight="8dip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/has_video" />
+ <LinearLayout
+ android:id="@+id/controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <Button
+ android:id="@+id/start_button"
+ style="@style/BottomBarButton"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/start_button" />
+ <Button
+ android:id="@+id/play_button"
+ style="@style/BottomBarButton"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/play_button" />
+ </LinearLayout>
+ <TextView
+ android:id="@+id/status"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/OneMedia/res/menu/main.xml b/tests/OneMedia/res/menu/main.xml
new file mode 100644
index 0000000..c002028
--- /dev/null
+++ b/tests/OneMedia/res/menu/main.xml
@@ -0,0 +1,9 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/action_settings"/>
+
+</menu>
diff --git a/tests/OneMedia/res/values/colors.xml b/tests/OneMedia/res/values/colors.xml
new file mode 100644
index 0000000..9b9dc2a
--- /dev/null
+++ b/tests/OneMedia/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+
+<resources>
+ <color name="title_color">#33B5E5</color>
+</resources>
diff --git a/tests/OneMedia/res/values/dimens.xml b/tests/OneMedia/res/values/dimens.xml
new file mode 100644
index 0000000..562edef
--- /dev/null
+++ b/tests/OneMedia/res/values/dimens.xml
@@ -0,0 +1,9 @@
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="title_size">22sp</dimen>
+ <dimen name="small_size">11sp</dimen>
+
+</resources>
diff --git a/tests/OneMedia/res/values/strings.xml b/tests/OneMedia/res/values/strings.xml
new file mode 100644
index 0000000..1b0cebb
--- /dev/null
+++ b/tests/OneMedia/res/values/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">OneMedia</string>
+ <string name="action_settings">Settings</string>
+ <string name="hello_world">Test app for trying out new media components</string>
+
+ <string name="start_button">Start</string>
+ <string name="play_button">Play</string>
+ <string name="media_content_hint">Content</string>
+ <string name="media_next_hint">Next content</string>
+ <string name="has_video">Is video</string>
+ <string name="has_duration">Has duration</string>
+
+</resources>
diff --git a/tests/OneMedia/res/values/styles.xml b/tests/OneMedia/res/values/styles.xml
new file mode 100644
index 0000000..60f3139
--- /dev/null
+++ b/tests/OneMedia/res/values/styles.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+ <style name="Title">
+ <item name="android:textSize">@dimen/title_size</item>
+ <item name="android:textColor">@color/title_color</item>
+ <item name="android:clickable">false</item>
+ <item name="android:longClickable">false</item>
+ </style>
+
+ <style name="Text">
+ <item name="android:textSize">@dimen/small_size</item>
+ <item name="android:textColor">@color/title_color</item>
+ <item name="android:clickable">false</item>
+ <item name="android:longClickable">false</item>
+ </style>
+
+ <style name="BottomBarButton">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:paddingTop">0dip</item>
+ <item name="android:paddingLeft">0dip</item>
+ <item name="android:paddingRight">0dip</item>
+ <item name="android:paddingBottom">0dip</item>
+ <item name="android:textSize">12sp</item>
+ <item name="android:textStyle">bold</item>
+ </style>
+</resources>
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.aidl
new file mode 100644
index 0000000..9bc3baa
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerCallback.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.onemedia;
+
+import android.media.MediaSessionToken;
+
+interface IPlayerCallback {
+ void onSessionChanged(in MediaSessionToken session);
+}
\ No newline at end of file
diff --git a/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
new file mode 100644
index 0000000..ab1d3fc
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/IPlayerService.aidl
@@ -0,0 +1,29 @@
+/* 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.onemedia;
+
+import android.media.MediaSessionToken;
+import android.os.Bundle;
+
+import com.android.onemedia.IPlayerCallback;
+import com.android.onemedia.playback.IRequestCallback;
+
+interface IPlayerService {
+ MediaSessionToken getSessionToken();
+ void registerCallback(in IPlayerCallback cb);
+ void unregisterCallback(in IPlayerCallback cb);
+ void sendRequest(String action, in Bundle params, in IRequestCallback cb);
+}
\ No newline at end of file
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
new file mode 100644
index 0000000..7ff81e4
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java
@@ -0,0 +1,144 @@
+package com.android.onemedia;
+
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.View;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.android.onemedia.playback.Renderer;
+
+public class OnePlayerActivity extends Activity {
+ private static final String TAG = "OnePlayerActivity";
+
+ protected PlayerController mPlayer;
+
+ private Button mStartButton;
+ private Button mPlayButton;
+ private TextView mStatusView;
+
+ private EditText mContentText;
+ private EditText mNextContentText;
+ private CheckBox mHasVideo;
+
+ private int mPlaybackState;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_one_player);
+ mPlayer = new PlayerController(this, OnePlayerService.getServiceIntent(this));
+
+
+ mStartButton = (Button) findViewById(R.id.start_button);
+ mPlayButton = (Button) findViewById(R.id.play_button);
+ mStatusView = (TextView) findViewById(R.id.status);
+ mContentText = (EditText) findViewById(R.id.content);
+ mNextContentText = (EditText) findViewById(R.id.next_content);
+ mHasVideo = (CheckBox) findViewById(R.id.has_video);
+
+ mStartButton.setOnClickListener(mButtonListener);
+ mPlayButton.setOnClickListener(mButtonListener);
+
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflate the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mPlayer.onResume();
+ mPlayer.setListener(mListener);
+ }
+
+ @Override
+ public void onPause() {
+ mPlayer.setListener(null);
+ mPlayer.onPause();
+ super.onPause();
+ }
+
+ private void setControlsEnabled(boolean enabled) {
+ mStartButton.setEnabled(enabled);
+ mPlayButton.setEnabled(enabled);
+ }
+
+ private View.OnClickListener mButtonListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.play_button:
+ Log.d(TAG, "Play button pressed, in state " + mPlaybackState);
+ if (mPlaybackState == Renderer.STATE_PAUSED
+ || mPlaybackState == Renderer.STATE_ENDED) {
+ mPlayer.play();
+ } else if (mPlaybackState == Renderer.STATE_PLAYING) {
+ mPlayer.pause();
+ }
+ break;
+ case R.id.start_button:
+ Log.d(TAG, "Start button pressed, in state " + mPlaybackState);
+ mPlayer.setContent(mContentText.getText().toString());
+ break;
+ }
+
+ }
+ };
+
+ private PlayerController.Listener mListener = new PlayerController.Listener() {
+ @Override
+ public void onSessionStateChange(int state) {
+ mPlaybackState = state;
+ boolean enablePlay = false;
+ switch (mPlaybackState) {
+ case Renderer.STATE_PLAYING:
+ mStatusView.setText("playing");
+ mPlayButton.setText("Pause");
+ enablePlay = true;
+ break;
+ case Renderer.STATE_PAUSED:
+ mStatusView.setText("paused");
+ mPlayButton.setText("Play");
+ enablePlay = true;
+ break;
+ case Renderer.STATE_ENDED:
+ mStatusView.setText("ended");
+ mPlayButton.setText("Play");
+ enablePlay = true;
+ break;
+ case Renderer.STATE_ERROR:
+ mStatusView.setText("error");
+ break;
+ case Renderer.STATE_PREPARING:
+ mStatusView.setText("preparing");
+ break;
+ case Renderer.STATE_READY:
+ mStatusView.setText("ready");
+ break;
+ case Renderer.STATE_STOPPED:
+ mStatusView.setText("stopped");
+ break;
+ }
+ mPlayButton.setEnabled(enablePlay);
+ }
+
+ @Override
+ public void onPlayerStateChange(int state) {
+ if (state == PlayerController.STATE_DISCONNECTED) {
+ setControlsEnabled(false);
+ } else if (state == PlayerController.STATE_CONNECTED) {
+ setControlsEnabled(true);
+ }
+ }
+ };
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java
new file mode 100644
index 0000000..01610cd
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java
@@ -0,0 +1,30 @@
+package com.android.onemedia;
+
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.ArrayList;
+
+/**
+ * TODO: Insert description here. (generated by epastern)
+ */
+public class OnePlayerService extends PlayerService {
+ private static final String TAG = "OnePlayerService";
+
+ public static Intent getServiceIntent(Context context) {
+ return new Intent(context, OnePlayerService.class).setPackage(
+ OnePlayerService.class.getPackage().getName());
+ }
+
+ @Override
+ protected Intent onCreateServiceIntent() {
+ return getServiceIntent(this);
+ }
+
+ @Override
+ protected ArrayList<String> getAllowedPackages() {
+ ArrayList<String> allowedPackages = new ArrayList<String>();
+ allowedPackages.add("com.android.onemedia");
+ return allowedPackages;
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
new file mode 100644
index 0000000..4ccc846
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java
@@ -0,0 +1,157 @@
+
+package com.android.onemedia;
+
+import android.media.MediaController;
+import android.media.MediaSessionManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.onemedia.playback.RequestUtils;
+
+public class PlayerController {
+ private static final String TAG = "PlayerSession";
+
+ public static final int STATE_DISCONNECTED = 0;
+ public static final int STATE_CONNECTED = 1;
+
+ protected MediaController mController;
+ protected IPlayerService mBinder;
+
+ private final Intent mServiceIntent;
+ private Context mContext;
+ private Listener mListener;
+ private SessionCallback mControllerCb;
+ private MediaSessionManager mManager;
+ private Handler mHandler = new Handler();
+
+ private boolean mResumed;
+
+ public PlayerController(Context context, Intent serviceIntent) {
+ mContext = context;
+ if (serviceIntent == null) {
+ mServiceIntent = new Intent(mContext, PlayerService.class);
+ } else {
+ mServiceIntent = serviceIntent;
+ }
+ mControllerCb = new SessionCallback();
+ mManager = (MediaSessionManager) context
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+
+ mResumed = false;
+ }
+
+ public void setListener(Listener listener) {
+ mListener = listener;
+ Log.d(TAG, "Listener set to " + listener + " session is " + mController);
+ if (mListener != null) {
+ mHandler = new Handler();
+ mListener.onPlayerStateChange(
+ mController == null ? STATE_DISCONNECTED : STATE_CONNECTED);
+ }
+ }
+
+ public void onResume() {
+ mResumed = true;
+ Log.d(TAG, "onResume. Binding to service with intent " + mServiceIntent.toString());
+ bindToService();
+ }
+
+ public void onPause() {
+ mResumed = false;
+ Log.d(TAG, "onPause, unbinding from service");
+ unbindFromService();
+ }
+
+ public void play() {
+ mController.sendMediaButton(KeyEvent.KEYCODE_MEDIA_PLAY);
+ }
+
+ public void pause() {
+ mController.sendMediaButton(KeyEvent.KEYCODE_MEDIA_PAUSE);
+ }
+
+ public void setContent(String source) {
+ RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder();
+ bob.setSource(source);
+ try {
+ mBinder.sendRequest(RequestUtils.ACTION_SET_CONTENT, bob.build(), null);
+ } catch (RemoteException e) {
+ Log.d(TAG, "setContent failed, service may have died.", e);
+ }
+ }
+
+ public void setNextContent(String source) {
+ RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder();
+ bob.setSource(source);
+ try {
+ mBinder.sendRequest(RequestUtils.ACTION_SET_NEXT_CONTENT, bob.build(), null);
+ } catch (RemoteException e) {
+ Log.d(TAG, "setNexctContent failed, service may have died.", e);
+ }
+ }
+
+ private void unbindFromService() {
+ mContext.unbindService(mServiceConnection);
+ }
+
+ private void bindToService() {
+ mContext.bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private ServiceConnection mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (mController != null) {
+ mController.removeCallback(mControllerCb);
+ }
+ mBinder = null;
+ mController = null;
+ Log.d(TAG, "Disconnected from PlayerService");
+
+ if (mListener != null) {
+ mListener.onPlayerStateChange(STATE_DISCONNECTED);
+ }
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mBinder = IPlayerService.Stub.asInterface(service);
+ Log.d(TAG, "service is " + service + " binder is " + mBinder);
+ try {
+ mController = new MediaController(mBinder.getSessionToken());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error getting session", e);
+ return;
+ }
+ mController.addCallback(mControllerCb, mHandler);
+ Log.d(TAG, "Ready to use PlayerService");
+
+ if (mListener != null) {
+ mListener.onPlayerStateChange(STATE_CONNECTED);
+ }
+ }
+ };
+
+ private class SessionCallback extends MediaController.Callback {
+ @Override
+ public void onPlaybackStateChange(int state) {
+ if (mListener != null) {
+ mListener.onSessionStateChange(state);
+ }
+ }
+ }
+
+ public interface Listener {
+ public void onSessionStateChange(int state);
+
+ public void onPlayerStateChange(int state);
+ }
+
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
new file mode 100644
index 0000000..0819077
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java
@@ -0,0 +1,102 @@
+package com.android.onemedia;
+
+import android.app.Service;
+import android.content.Intent;
+import android.media.MediaSessionToken;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.onemedia.playback.IRequestCallback;
+import com.android.onemedia.playback.RequestUtils;
+
+import java.util.ArrayList;
+
+public class PlayerService extends Service {
+ private static final String TAG = "PlayerService";
+
+ private PlayerBinder mBinder;
+ private PlayerSession mSession;
+ private Intent mIntent;
+
+ private ArrayList<IPlayerCallback> mCbs = new ArrayList<IPlayerCallback>();
+
+ @Override
+ public void onCreate() {
+ mIntent = onCreateServiceIntent();
+ mSession = onCreatePlayerController();
+ mSession.createSession();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mBinder == null) {
+ mBinder = new PlayerBinder();
+ }
+ return mBinder;
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ mSession.onDestroy();
+ }
+
+ protected Intent onCreateServiceIntent() {
+ return new Intent(this, PlayerService.class).setPackage(getBasePackageName());
+ }
+
+ protected PlayerSession onCreatePlayerController() {
+ return new PlayerSession(this);
+ }
+
+ protected ArrayList<String> getAllowedPackages() {
+ return null;
+ }
+
+ public class PlayerBinder extends IPlayerService.Stub {
+ @Override
+ public void sendRequest(String action, Bundle params, IRequestCallback cb) {
+ if (RequestUtils.ACTION_SET_CONTENT.equals(action)) {
+ mSession.setContent(params);
+ } else if (RequestUtils.ACTION_SET_NEXT_CONTENT.equals(action)) {
+ mSession.setNextContent(params);
+ }
+ }
+
+ @Override
+ public void registerCallback(final IPlayerCallback cb) throws RemoteException {
+ if (!mCbs.contains(cb)) {
+ mCbs.add(cb);
+ cb.asBinder().linkToDeath(new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ mCbs.remove(cb);
+ }
+ }, 0);
+ }
+ try {
+ cb.onSessionChanged(getSessionToken());
+ } catch (RemoteException e) {
+ mCbs.remove(cb);
+ throw e;
+ }
+ }
+
+ @Override
+ public void unregisterCallback(IPlayerCallback cb) throws RemoteException {
+ mCbs.remove(cb);
+ }
+
+ @Override
+ public MediaSessionToken getSessionToken() throws RemoteException {
+ // TODO(epastern): Auto-generated method stub
+ return mSession.getSessionToken();
+ }
+ }
+
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
new file mode 100644
index 0000000..25a8f0d
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java
@@ -0,0 +1,117 @@
+package com.android.onemedia;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.MediaSession;
+import android.media.MediaSessionManager;
+import android.media.MediaSessionToken;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.onemedia.playback.LocalRenderer;
+import com.android.onemedia.playback.Renderer;
+import com.android.onemedia.playback.RendererFactory;
+
+public class PlayerSession {
+ private static final String TAG = "PlayerController";
+
+ protected MediaSession mSession;
+ protected Context mContext;
+ protected RendererFactory mRendererFactory;
+ protected LocalRenderer mRenderer;
+ protected ControllerCb mCallback;
+ protected RenderListener mRenderListener;
+
+ public PlayerSession(Context context) {
+ mContext = context;
+ mRendererFactory = new RendererFactory();
+ mRenderer = new LocalRenderer(context, null);
+ mCallback = new ControllerCb();
+ mRenderListener = new RenderListener();
+
+ mRenderer.registerListener(mRenderListener);
+ }
+
+ public void createSession() {
+ if (mSession != null) {
+ mSession.release();
+ }
+ MediaSessionManager man = (MediaSessionManager) mContext
+ .getSystemService(Context.MEDIA_SESSION_SERVICE);
+ Log.d(TAG, "Creating session for package " + mContext.getBasePackageName());
+ mSession = man.createSession("OneMedia");
+ mSession.addCallback(mCallback);
+ }
+
+ public void onDestroy() {
+ if (mSession != null) {
+ mSession.release();
+ }
+ if (mRenderer != null) {
+ mRenderer.unregisterListener(mRenderListener);
+ mRenderer.onDestroy();
+ }
+ }
+
+ public MediaSessionToken getSessionToken() {
+ return mSession.getSessionToken();
+ }
+
+ public void setContent(Bundle request) {
+ mRenderer.setContent(request);
+ }
+
+ public void setNextContent(Bundle request) {
+ mRenderer.setNextContent(request);
+ }
+
+ protected class RenderListener implements Renderer.Listener {
+
+ @Override
+ public void onError(int type, int extra, Bundle extras, Throwable error) {
+ mSession.setPlaybackState(Renderer.STATE_ERROR);
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ mSession.setPlaybackState(newState);
+ }
+
+ @Override
+ public void onBufferingUpdate(int percent) {
+ }
+
+ @Override
+ public void onFocusLost() {
+ mSession.setPlaybackState(Renderer.STATE_PAUSED);
+ }
+
+ @Override
+ public void onNextStarted() {
+ }
+
+ }
+
+ protected class ControllerCb extends MediaSession.Callback {
+
+ @Override
+ public void onMediaButton(Intent mediaRequestIntent) {
+ if (Intent.ACTION_MEDIA_BUTTON.equals(mediaRequestIntent.getAction())) {
+ KeyEvent event = (KeyEvent) mediaRequestIntent
+ .getParcelableExtra(Intent.EXTRA_KEY_EVENT);
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ Log.d(TAG, "play button received");
+ mRenderer.onPlay();
+ break;
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ Log.d(TAG, "pause button received");
+ mRenderer.onPause();
+ break;
+ }
+ }
+ }
+ }
+
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/IRequestCallback.aidl b/tests/OneMedia/src/com/android/onemedia/playback/IRequestCallback.aidl
new file mode 100644
index 0000000..c5a30a8
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/IRequestCallback.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.onemedia.playback;
+
+import android.os.Bundle;
+
+oneway interface IRequestCallback {
+ void onResult(in Bundle result);
+}
\ No newline at end of file
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
new file mode 100644
index 0000000..7493366
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
@@ -0,0 +1,703 @@
+package com.android.onemedia.playback;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioManager.OnAudioFocusChangeListener;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnBufferingUpdateListener;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
+import android.net.http.AndroidHttpClient;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Helper class for wrapping a MediaPlayer and doing a lot of the default work
+ * to play audio. This class is not currently thread safe and all calls to it
+ * should be made on the same thread.
+ */
+public class LocalRenderer extends Renderer implements OnPreparedListener,
+ OnBufferingUpdateListener, OnCompletionListener, OnErrorListener,
+ OnAudioFocusChangeListener {
+ private static final String TAG = "MediaPlayerManager";
+ private static final boolean DEBUG = true;
+ private static long sDebugInstanceId = 0;
+
+ private static final String[] SUPPORTED_FEATURES = {
+ FEATURE_SET_CONTENT,
+ FEATURE_SET_NEXT_CONTENT,
+ FEATURE_PLAY,
+ FEATURE_PAUSE,
+ FEATURE_NEXT,
+ FEATURE_PREVIOUS,
+ FEATURE_SEEK_TO,
+ FEATURE_STOP
+ };
+
+ /**
+ * These are the states where it is valid to call play directly on the
+ * MediaPlayer.
+ */
+ private static final int CAN_PLAY = STATE_READY | STATE_PAUSED | STATE_ENDED;
+ /**
+ * These are the states where we expect the MediaPlayer to be ready in the
+ * future, so we can set a flag to start playing when it is.
+ */
+ private static final int CAN_READY_PLAY = STATE_INIT | STATE_PREPARING;
+ /**
+ * The states when it is valid to call pause on the MediaPlayer.
+ */
+ private static final int CAN_PAUSE = STATE_PLAYING;
+ /**
+ * The states where it is valid to call seek on the MediaPlayer.
+ */
+ private static final int CAN_SEEK = STATE_READY | STATE_PLAYING | STATE_PAUSED | STATE_ENDED;
+ /**
+ * The states where we expect the MediaPlayer to be ready in the future and
+ * can store a seek position to set later.
+ */
+ private static final int CAN_READY_SEEK = STATE_INIT | STATE_PREPARING;
+ /**
+ * The states where it is valid to call stop on the MediaPlayer.
+ */
+ private static final int CAN_STOP = STATE_READY | STATE_PLAYING | STATE_PAUSED | STATE_ENDED;
+ /**
+ * The states where it is valid to get the current play position and the
+ * duration from the MediaPlayer.
+ */
+ private static final int CAN_GET_POSITION = STATE_READY | STATE_PLAYING | STATE_PAUSED;
+
+
+
+ private class PlayerContent {
+ public final String source;
+ public final Map<String, String> headers;
+
+ public PlayerContent(String source, Map<String, String> headers) {
+ this.source = source;
+ this.headers = headers;
+ }
+ }
+
+ private class AsyncErrorRetriever extends AsyncTask<HttpGet, Void, Void> {
+ private final long errorId;
+ private boolean closeHttpClient;
+
+ public AsyncErrorRetriever(long errorId) {
+ this.errorId = errorId;
+ closeHttpClient = false;
+ }
+
+ public boolean cancelRequestLocked(boolean closeHttp) {
+ closeHttpClient = closeHttp;
+ return this.cancel(false);
+ }
+
+ @Override
+ protected Void doInBackground(HttpGet[] params) {
+ synchronized (mErrorLock) {
+ if (isCancelled() || mHttpClient == null) {
+ if (mErrorRetriever == this) {
+ mErrorRetriever = null;
+ }
+ return null;
+ }
+ mSafeToCloseClient = false;
+ }
+ final PlaybackError error = new PlaybackError();
+ try {
+ HttpResponse response = mHttpClient.execute(params[0]);
+ synchronized (mErrorLock) {
+ if (mErrorId != errorId || mError == null) {
+ // A new error has occurred, abort
+ return null;
+ }
+ error.type = mError.type;
+ error.extra = mError.extra;
+ error.errorMessage = mError.errorMessage;
+ }
+ final int code = response.getStatusLine().getStatusCode();
+ if (code >= 300) {
+ error.extra = code;
+ }
+ final Bundle errorExtras = new Bundle();
+ Header[] headers = response.getAllHeaders();
+ if (headers != null && headers.length > 0) {
+ for (Header header : headers) {
+ errorExtras.putString(header.getName(), header.getValue());
+ }
+ error.errorExtras = errorExtras;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "IOException requesting from server, unable to get more exact error");
+ } finally {
+ synchronized (mErrorLock) {
+ mSafeToCloseClient = true;
+ if (mErrorRetriever == this) {
+ mErrorRetriever = null;
+ }
+ if (isCancelled()) {
+ if (closeHttpClient) {
+ mHttpClient.close();
+ mHttpClient = null;
+ }
+ return null;
+ }
+ }
+ }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mErrorLock) {
+ if (mErrorId == errorId) {
+ setError(error.type, error.extra, error.errorExtras, null);
+ }
+ }
+ }
+ });
+ return null;
+ }
+ }
+
+ private int mState = STATE_INIT;
+
+ private AudioManager mAudioManager;
+ private MediaPlayer mPlayer;
+ private PlayerContent mContent;
+ private MediaPlayer mNextPlayer;
+ private PlayerContent mNextContent;
+ private SurfaceHolder mHolder;
+ private SurfaceHolder.Callback mHolderCB;
+ private Context mContext;
+
+ private Handler mHandler = new Handler();
+
+ private AndroidHttpClient mHttpClient = AndroidHttpClient.newInstance("TUQ");
+ // The ongoing error request thread if there is one. This should only be
+ // modified while mErrorLock is held.
+ private AsyncErrorRetriever mErrorRetriever;
+ // This is set to false while a server request is being made to retrieve
+ // the current error. It should only be set while mErrorLock is held.
+ private boolean mSafeToCloseClient = true;
+ private final Object mErrorLock = new Object();
+ // A tracking id for the current error. This should only be modified while
+ // mErrorLock is held.
+ private long mErrorId = 0;
+ // The current error state of this player. This is cleared when the state
+ // leaves an error state and set when it enters one. This should only be
+ // modified when mErrorLock is held.
+ private PlaybackError mError;
+
+ private boolean mPlayOnReady;
+ private int mSeekOnReady;
+ private boolean mHasAudioFocus;
+ private long mDebugId = sDebugInstanceId++;
+
+ public LocalRenderer(Context context, Bundle params) {
+ super(context, params);
+ mContext = context;
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ @Override
+ protected void initFeatures(Bundle params) {
+ for (String feature : SUPPORTED_FEATURES) {
+ mFeatures.add(feature);
+ }
+ }
+
+ /**
+ * Call this when completely finished with the MediaPlayerManager to have it
+ * clean up. The instance may not be used again after this is called.
+ */
+ @Override
+ public void onDestroy() {
+ synchronized (mErrorLock) {
+ if (DEBUG) {
+ Log.d(TAG, "onDestroy, error retriever? " + mErrorRetriever + " safe to close? "
+ + mSafeToCloseClient + " client? " + mHttpClient);
+ }
+ if (mErrorRetriever != null) {
+ mErrorRetriever.cancelRequestLocked(true);
+ mErrorRetriever = null;
+ }
+ // Increment the error id to ensure no errors are sent after this
+ // point.
+ mErrorId++;
+ if (mSafeToCloseClient) {
+ mHttpClient.close();
+ mHttpClient = null;
+ }
+ }
+ }
+
+ @Override
+ public void onPrepared(MediaPlayer player) {
+ if (!isCurrentPlayer(player)) {
+ return;
+ }
+ setState(STATE_READY);
+ if (DEBUG) {
+ Log.d(TAG, mDebugId + ": Finished preparing, seekOnReady is " + mSeekOnReady);
+ }
+ if (mSeekOnReady >= 0) {
+ onSeekTo(mSeekOnReady);
+ mSeekOnReady = -1;
+ }
+ if (mPlayOnReady) {
+ player.start();
+ setState(STATE_PLAYING);
+ }
+ }
+
+ @Override
+ public void onBufferingUpdate(MediaPlayer player, int percent) {
+ if (!isCurrentPlayer(player)) {
+ return;
+ }
+ pushOnBufferingUpdate(percent);
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer player) {
+ if (!isCurrentPlayer(player)) {
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, mDebugId + ": Completed item. Have next item? " + (mNextPlayer != null));
+ }
+ if (mNextPlayer != null) {
+ if (mPlayer != null) {
+ mPlayer.release();
+ }
+ mPlayer = mNextPlayer;
+ mContent = mNextContent;
+ mNextPlayer = null;
+ mNextContent = null;
+ pushOnNextStarted();
+ return;
+ }
+ setState(STATE_ENDED);
+ }
+
+ @Override
+ public boolean onError(MediaPlayer player, int what, int extra) {
+ if (!isCurrentPlayer(player)) {
+ return false;
+ }
+ if (DEBUG) {
+ Log.d(TAG, mDebugId + ": Entered error state, what: " + what + " extra: " + extra);
+ }
+ synchronized (mErrorLock) {
+ ++mErrorId;
+ mError = new PlaybackError();
+ mError.type = what;
+ mError.extra = extra;
+ }
+
+ if (what == MediaPlayer.MEDIA_ERROR_UNKNOWN && extra == MediaPlayer.MEDIA_ERROR_IO
+ && mContent != null && mContent.source.startsWith("http")) {
+ HttpGet request = new HttpGet(mContent.source);
+ if (mContent.headers != null) {
+ for (String key : mContent.headers.keySet()) {
+ request.addHeader(key, mContent.headers.get(key));
+ }
+ }
+ synchronized (mErrorLock) {
+ if (mErrorRetriever != null) {
+ mErrorRetriever.cancelRequestLocked(false);
+ }
+ mErrorRetriever = new AsyncErrorRetriever(mErrorId);
+ mErrorRetriever.execute(request);
+ }
+ } else {
+ setError(what, extra, null, null);
+ }
+ return true;
+ }
+
+ @Override
+ public void onAudioFocusChange(int focusChange) {
+ // TODO figure out appropriate logic for handling focus loss at the TUQ
+ // level.
+ switch (focusChange) {
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ if (mState == STATE_PLAYING) {
+ onPause();
+ mPlayOnReady = true;
+ }
+ mHasAudioFocus = false;
+ break;
+ case AudioManager.AUDIOFOCUS_LOSS:
+ if (mState == STATE_PLAYING) {
+ onPause();
+ mPlayOnReady = false;
+ }
+ pushOnFocusLost();
+ mHasAudioFocus = false;
+ break;
+ case AudioManager.AUDIOFOCUS_GAIN:
+ mHasAudioFocus = true;
+ if (mPlayOnReady) {
+ onPlay();
+ }
+ break;
+ default:
+ Log.d(TAG, "Unknown focus change event " + focusChange);
+ break;
+ }
+ }
+
+ @Override
+ public void setContent(Bundle request) {
+ setContent(request, null);
+ }
+
+ /**
+ * Prepares the player for the given playback request. If the holder is null
+ * it is assumed this is an audio only source. If playOnReady is set to true
+ * the media will begin playing as soon as it can.
+ */
+ public void setContent(Bundle request, SurfaceHolder holder) {
+ String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
+ Map<String, String> headers = null; // request.mHeaders;
+ boolean playOnReady = true; // request.mPlayOnReady;
+ if (DEBUG) {
+ Log.d(TAG, mDebugId + ": Settings new content. Have a player? " + (mPlayer != null)
+ + " have a next player? " + (mNextPlayer != null));
+ }
+ cleanUpPlayer();
+ setState(STATE_PREPARING);
+ mPlayOnReady = playOnReady;
+ mSeekOnReady = -1;
+ final MediaPlayer newPlayer = new MediaPlayer();
+
+ requestAudioFocus();
+
+ mPlayer = newPlayer;
+ mContent = new PlayerContent(source, headers);
+ try {
+ if (headers != null) {
+ Uri sourceUri = Uri.parse(source);
+ newPlayer.setDataSource(mContext, sourceUri, headers);
+ } else {
+ newPlayer.setDataSource(source);
+ }
+ } catch (Exception e) {
+ setError(Listener.ERROR_LOAD_FAILED, 0, null, e);
+ return;
+ }
+ if (isHolderReady(holder, newPlayer)) {
+ preparePlayer(newPlayer, true);
+ }
+ }
+
+ @Override
+ public void setNextContent(Bundle request) {
+ String source = request.getString(RequestUtils.EXTRA_KEY_SOURCE);
+ Map<String, String> headers = null; // request.mHeaders;
+
+ // TODO support video
+
+ if (DEBUG) {
+ Log.d(TAG, mDebugId + ": Setting next content. Have player? " + (mPlayer != null)
+ + " have next player? " + (mNextPlayer != null));
+ }
+
+ if (mPlayer == null) {
+ // The manager isn't being used to play anything, don't try to
+ // set a next.
+ return;
+ }
+ if (mNextPlayer != null) {
+ // Before setting up the new one clear out the old one and release
+ // it to ensure it doesn't play.
+ mPlayer.setNextMediaPlayer(null);
+ mNextPlayer.release();
+ mNextPlayer = null;
+ mNextContent = null;
+ }
+ if (source == null) {
+ // If there's no new content we're done
+ return;
+ }
+ final MediaPlayer newPlayer = new MediaPlayer();
+
+ try {
+ if (headers != null) {
+ Uri sourceUri = Uri.parse(source);
+ newPlayer.setDataSource(mContext, sourceUri, headers);
+ } else {
+ newPlayer.setDataSource(source);
+ }
+ } catch (Exception e) {
+ newPlayer.release();
+ // Don't return an error until we get to this item in playback
+ return;
+ }
+
+ if (preparePlayer(newPlayer, false)) {
+ mPlayer.setNextMediaPlayer(newPlayer);
+ mNextPlayer = newPlayer;
+ mNextContent = new PlayerContent(source, headers);
+ }
+ }
+
+ private void requestAudioFocus() {
+ int result = mAudioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
+ AudioManager.AUDIOFOCUS_GAIN);
+ mHasAudioFocus = result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+ }
+
+ /**
+ * Start the player if possible or queue it to play when ready. If the
+ * player is in a state where it will never be ready returns false.
+ *
+ * @return true if the content was started or will be started later
+ */
+ @Override
+ public boolean onPlay() {
+ MediaPlayer player = mPlayer;
+ if (player != null && mState == STATE_PLAYING) {
+ // already playing, just return
+ return true;
+ }
+ if (!mHasAudioFocus) {
+ requestAudioFocus();
+ }
+ if (player != null && canPlay()) {
+ player.start();
+ setState(STATE_PLAYING);
+ } else if (canReadyPlay()) {
+ mPlayOnReady = true;
+ } else if (!isPlaying()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Pause the player if possible or set it to not play when ready. If the
+ * player is in a state where it will never be ready returns false.
+ *
+ * @return true if the content was paused or will wait to play when ready
+ * later
+ */
+ @Override
+ public boolean onPause() {
+ MediaPlayer player = mPlayer;
+ if (player != null && (mState & CAN_PAUSE) != 0) {
+ player.pause();
+ setState(STATE_PAUSED);
+ } else if ((mState & CAN_READY_PLAY) != 0) {
+ mPlayOnReady = false;
+ } else if (!isPaused()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Seek to a given position in the media. If the seek succeeded or will be
+ * performed when loading is complete returns true. If the position is not
+ * in range or the player will never be ready returns false.
+ *
+ * @param position The position to seek to in milliseconds
+ * @return true if playback was moved or will be moved when ready
+ */
+ @Override
+ public boolean onSeekTo(int position) {
+ MediaPlayer player = mPlayer;
+ if (player != null && (mState & CAN_SEEK) != 0) {
+ if (position < 0 || position >= getDuration()) {
+ return false;
+ } else {
+ if (mState == STATE_ENDED) {
+ player.start();
+ player.pause();
+ setState(STATE_PAUSED);
+ }
+ player.seekTo(position);
+ }
+ } else if ((mState & CAN_READY_SEEK) != 0) {
+ mSeekOnReady = position;
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Stop the player. It cannot be used again until
+ * {@link #setContent(String, boolean)} is called.
+ *
+ * @return true if stopping the player succeeded
+ */
+ @Override
+ public boolean onStop() {
+ cleanUpPlayer();
+ setState(STATE_STOPPED);
+ return true;
+ }
+
+ public boolean isPlaying() {
+ return mState == STATE_PLAYING;
+ }
+
+ public boolean isPaused() {
+ return mState == STATE_PAUSED;
+ }
+
+ @Override
+ public long getSeekPosition() {
+ return ((mState & CAN_GET_POSITION) == 0) ? -1 : mPlayer.getCurrentPosition();
+ }
+
+ @Override
+ public long getDuration() {
+ return ((mState & CAN_GET_POSITION) == 0) ? -1 : mPlayer.getDuration();
+ }
+
+ private boolean canPlay() {
+ return ((mState & CAN_PLAY) != 0) && mHasAudioFocus;
+ }
+
+ private boolean canReadyPlay() {
+ return (mState & CAN_PLAY) != 0 || (mState & CAN_READY_PLAY) != 0;
+ }
+
+ /**
+ * Sends a state update if the listener exists
+ */
+ private void setState(int state) {
+ if (state == mState) {
+ return;
+ }
+ Log.d(TAG, "Entering state " + state + " from state " + mState);
+ mState = state;
+ if (state != STATE_ERROR) {
+ // Don't notify error here, it'll get sent via onError
+ pushOnStateChanged(state);
+ }
+ }
+
+ private boolean preparePlayer(final MediaPlayer player, boolean current) {
+ player.setOnPreparedListener(this);
+ player.setOnBufferingUpdateListener(this);
+ player.setOnCompletionListener(this);
+ player.setOnErrorListener(this);
+ try {
+ player.prepareAsync();
+ if (current) {
+ setState(STATE_PREPARING);
+ }
+ } catch (IllegalStateException e) {
+ if (current) {
+ setError(Listener.ERROR_PREPARE_ERROR, 0, null, e);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param extra
+ * @param e
+ */
+ private void setError(int type, int extra, Bundle extras, Exception e) {
+ setState(STATE_ERROR);
+ pushOnError(type, extra, extras, e);
+ cleanUpPlayer();
+ return;
+ }
+
+ /**
+ * Checks if the holder is ready and either sets up a callback to wait for
+ * it or sets it directly. If
+ *
+ * @param holder
+ * @param player
+ * @return
+ */
+ private boolean isHolderReady(final SurfaceHolder holder, final MediaPlayer player) {
+ mHolder = holder;
+ if (holder != null) {
+ if (holder.getSurface() != null && holder.getSurface().isValid()) {
+ player.setDisplay(holder);
+ return true;
+ } else {
+ Log.w(TAG, "Holder not null, waiting for it to be ready");
+ // If the holder isn't ready yet add a callback to set the
+ // holder when it's ready.
+ SurfaceHolder.Callback cb = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceDestroyed(SurfaceHolder arg0) {
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder arg0) {
+ if (player.equals(mPlayer)) {
+ player.setDisplay(arg0);
+ preparePlayer(player, true);
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
+ }
+ };
+ mHolderCB = cb;
+ holder.addCallback(cb);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void cleanUpPlayer() {
+ if (DEBUG) {
+ Log.d(TAG, mDebugId + ": Cleaning up current player");
+ }
+ synchronized (mErrorLock) {
+ mError = null;
+ if (mErrorRetriever != null) {
+ mErrorRetriever.cancelRequestLocked(false);
+ // Don't set to null as we may need to cancel again with true if
+ // the object gets destroyed.
+ }
+ }
+ mAudioManager.abandonAudioFocus(this);
+
+ SurfaceHolder.Callback cb = mHolderCB;
+ mHolderCB = null;
+ SurfaceHolder holder = mHolder;
+ mHolder = null;
+ if (holder != null && cb != null) {
+ holder.removeCallback(cb);
+ }
+
+ MediaPlayer player = mPlayer;
+ mPlayer = null;
+ if (player != null) {
+ player.reset();
+ player.release();
+ }
+ }
+
+ private boolean isCurrentPlayer(MediaPlayer player) {
+ return player.equals(mPlayer);
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java b/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java
new file mode 100644
index 0000000..f9e6794
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/MediaItem.java
@@ -0,0 +1,59 @@
+package com.android.onemedia.playback;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.v7.media.MediaItemMetadata;
+
+/**
+ * TODO: Insert description here. (generated by epastern)
+ */
+public class MediaItem implements Parcelable {
+ private Bundle mBundle;
+
+ public MediaItem() {
+
+ }
+
+ private MediaItem(Parcel in) {
+ mBundle = in.readBundle();
+ }
+
+ public String getTitle() {
+ return mBundle.getString(MediaItemMetadata.KEY_TITLE);
+ }
+
+ public String getArtist() {
+ return mBundle.getString(MediaItemMetadata.KEY_ALBUM_ARTIST);
+ }
+
+ /* (non-Javadoc)
+ * @see android.os.Parcelable#describeContents()
+ */
+ @Override
+ public int describeContents() {
+ // TODO(epastern): Auto-generated method stub
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see android.os.Parcelable#writeToParcel(android.os.Parcel, int)
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBundle(mBundle);
+ }
+
+ public static final Parcelable.Creator<MediaItem> CREATOR
+ = new Parcelable.Creator<MediaItem>() {
+ public MediaItem createFromParcel(Parcel in) {
+ return new MediaItem(in);
+ }
+
+ public MediaItem[] newArray(int size) {
+ return new MediaItem[size];
+ }
+ };
+
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java b/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java
new file mode 100644
index 0000000..72d936c
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/PlaybackError.java
@@ -0,0 +1,10 @@
+package com.android.onemedia.playback;
+
+import android.os.Bundle;
+
+public class PlaybackError {
+ public int type;
+ public int extra;
+ public String errorMessage;
+ public Bundle errorExtras;
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java b/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java
new file mode 100644
index 0000000..2451bdf
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/Renderer.java
@@ -0,0 +1,199 @@
+package com.android.onemedia.playback;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO: Insert description here. (generated by epastern)
+ */
+public abstract class Renderer {
+ public static final String FEATURE_SET_CONTENT = "com.android.media.SET_CONTENT";
+ public static final String FEATURE_SET_NEXT_CONTENT = "com.android.media.SET_NEXT_CONTENT";
+ public static final String FEATURE_PLAY = "com.android.media.PLAY";
+ public static final String FEATURE_PAUSE = "com.android.media.PAUSE";
+ public static final String FEATURE_NEXT = "com.android.media.NEXT";
+ public static final String FEATURE_PREVIOUS = "com.android.media.PREVIOUS";
+ public static final String FEATURE_SEEK_TO = "com.android.media.SEEK_TO";
+ public static final String FEATURE_STOP = "com.android.media.STOP";
+ // TODO move states somewhere else
+ public static final int STATE_ERROR = 0;
+ /**
+ * The state MediaPlayerManager starts in before any action has been
+ * performed.
+ */
+ public static final int STATE_INIT = 1 << 0;
+ /**
+ * Indicates the source has been set and it is being prepared/buffered
+ * before starting playback.
+ */
+ public static final int STATE_PREPARING = 1 << 1;
+ /**
+ * The media is ready and playback can be started.
+ */
+ public static final int STATE_READY = 1 << 2;
+ /**
+ * The media is currently playing.
+ */
+ public static final int STATE_PLAYING = 1 << 3;
+ /**
+ * The media is currently paused.
+ */
+ public static final int STATE_PAUSED = 1 << 4;
+ /**
+ * The service has been stopped and cannot be started again until a new
+ * source has been set.
+ */
+ public static final int STATE_STOPPED = 1 << 5;
+ /**
+ * The playback has reached the end. It can be restarted by calling play().
+ */
+ public static final int STATE_ENDED = 1 << 6;
+
+ // TODO decide on proper way of describing features
+ protected List<String> mFeatures = new ArrayList<String>();
+ protected List<Listener> mListeners = new ArrayList<Listener>();
+
+ public Renderer(Context context, Bundle params) {
+ onCreate(params);
+ initFeatures(params);
+ }
+
+ abstract public void setContent(Bundle request);
+
+ public void onCreate(Bundle params) {
+ // Do nothing by default
+ }
+
+ public void setNextContent(Bundle request) {
+ throw new UnsupportedOperationException("setNextContent() is not supported.");
+ }
+
+ public List<String> getFeatures() {
+ return mFeatures;
+ }
+
+ public boolean onPlay() {
+ throw new UnsupportedOperationException("play is not supported.");
+ }
+
+ public boolean onPause() {
+ throw new UnsupportedOperationException("pause is not supported.");
+ }
+
+ public boolean onNext() {
+ throw new UnsupportedOperationException("next is not supported.");
+ }
+
+ public boolean onPrevious() {
+ throw new UnsupportedOperationException("previous is not supported.");
+ }
+
+ public boolean onStop() {
+ throw new UnsupportedOperationException("stop is not supported.");
+ }
+
+ public boolean onSeekTo(int time) {
+ throw new UnsupportedOperationException("seekTo is not supported.");
+ }
+
+ public long getSeekPosition() {
+ throw new UnsupportedOperationException("getSeekPosition is not supported.");
+ }
+
+ public long getDuration() {
+ throw new UnsupportedOperationException("getDuration is not supported.");
+ }
+
+ public int getPlayState() {
+ throw new UnsupportedOperationException("getPlayState is not supported.");
+ }
+
+ public void onDestroy() {
+ // Do nothing by default
+ }
+
+ public void registerListener(Listener listener) {
+ if (!mListeners.contains(listener)) {
+ mListeners.add(listener);
+ }
+ }
+
+ public void unregisterListener(Listener listener) {
+ mListeners.remove(listener);
+ }
+
+ protected void initFeatures(Bundle params) {
+ mFeatures.add(FEATURE_SET_CONTENT);
+ }
+
+ protected void pushOnError(int type, int extra, Bundle extras, Throwable error) {
+ for (Listener listener : mListeners) {
+ listener.onError(type, extra, extras, error);
+ }
+ }
+
+ protected void pushOnStateChanged(int newState) {
+ for (Listener listener : mListeners) {
+ listener.onStateChanged(newState);
+ }
+ }
+
+ protected void pushOnBufferingUpdate(int percent) {
+ for (Listener listener : mListeners) {
+ listener.onBufferingUpdate(percent);
+ }
+ }
+
+ protected void pushOnFocusLost() {
+ for (Listener listener : mListeners) {
+ listener.onFocusLost();
+ }
+ }
+
+ protected void pushOnNextStarted() {
+ for (Listener listener : mListeners) {
+ listener.onNextStarted();
+ }
+ }
+
+ public interface Listener {
+ public static final int ERROR_LOAD_FAILED = 1770;
+ public static final int ERROR_PREPARE_ERROR = 1771;
+ public static final int ERROR_PLAYBACK_FAILED = 1772;
+
+ /**
+ * When an error occurs onError will be called but not onStateChanged.
+ * The Manager will remain in the error state until
+ * {@link #setContent()} is called again.
+ */
+ public void onError(int type, int extra, Bundle extras,
+ Throwable error);
+
+ /**
+ * onStateChanged will be called whenever the state of the manager
+ * transitions except to an error state.
+ */
+ public void onStateChanged(int newState);
+
+ /**
+ * This is a passthrough of
+ * {@link MediaPlayer.OnBufferingUpdateListener}.
+ */
+ public void onBufferingUpdate(int percent);
+
+ /**
+ * Called when audio focus is lost and it is not transient or ducking.
+ */
+ public void onFocusLost();
+
+ /**
+ * Called when the next item was started playing. Only called if a next
+ * item has been set and the current item has ended.
+ */
+ public void onNextStarted();
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/RendererFactory.java b/tests/OneMedia/src/com/android/onemedia/playback/RendererFactory.java
new file mode 100644
index 0000000..f333fce
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/RendererFactory.java
@@ -0,0 +1,22 @@
+package com.android.onemedia.playback;
+
+import android.content.Context;
+import android.media.MediaRouter;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * TODO: Insert description here.
+ */
+public class RendererFactory {
+ private static final String TAG = "RendererFactory";
+
+ public Renderer createRenderer(MediaRouter.RouteInfo route, Context context, Bundle params) {
+ if (route.getPlaybackType() == MediaRouter.RouteInfo.PLAYBACK_TYPE_LOCAL) {
+ return new LocalRenderer(context, params);
+ }
+ Log.e(TAG, "Unable to create renderer for route of playback type "
+ + route.getPlaybackType());
+ return null;
+ }
+}
diff --git a/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
new file mode 100644
index 0000000..9b50dad
--- /dev/null
+++ b/tests/OneMedia/src/com/android/onemedia/playback/RequestUtils.java
@@ -0,0 +1,53 @@
+package com.android.onemedia.playback;
+
+import android.os.Bundle;
+import android.support.v7.media.MediaItemMetadata;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * TODO: Insert description here. (generated by epastern)
+ */
+public class RequestUtils {
+ public static final String ACTION_SET_CONTENT = "set_content";
+ public static final String ACTION_SET_NEXT_CONTENT = "set_next_content";
+
+ public static final String EXTRA_KEY_SOURCE = "source";
+ public static final String EXTRA_KEY_METADATA = "metadata";
+ public static final String EXTRA_KEY_HEADERS = "headers";
+
+ private RequestUtils() {
+ }
+
+ public static class ContentBuilder {
+ private Bundle mBundle;
+
+ public ContentBuilder() {
+ mBundle = new Bundle();
+ }
+
+ public ContentBuilder setSource(String source) {
+ mBundle.putString(EXTRA_KEY_SOURCE, source);
+ return this;
+ }
+
+ /**
+ * @see MediaItemMetadata
+ * @param metadata The metadata for this item
+ */
+ public ContentBuilder setMetadata(Bundle metadata) {
+ mBundle.putBundle(EXTRA_KEY_METADATA, metadata);
+ return this;
+ }
+
+ public ContentBuilder setHeaders(HashMap<String, String> headers) {
+ mBundle.putSerializable(EXTRA_KEY_HEADERS, headers);
+ return this;
+ }
+
+ public Bundle build() {
+ return mBundle;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
index ca710cd..4603b63 100644
--- a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -48,14 +48,14 @@
}
@LayoutlibDelegate
- /*package*/ static int nGetMultipleIntMethod(Class<?> targetClass, String methodName,
+ /*package*/ static long nGetMultipleIntMethod(Class<?> targetClass, String methodName,
int numParams) {
// TODO: return the right thing.
return 0;
}
@LayoutlibDelegate
- /*package*/ static int nGetMultipleFloatMethod(Class<?> targetClass, String methodName,
+ /*package*/ static long nGetMultipleFloatMethod(Class<?> targetClass, String methodName,
int numParams) {
// TODO: return the right thing.
return 0;
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index c3e06d2..dd573be 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -155,6 +155,11 @@
@Override
public Drawable getDrawable(int id) throws NotFoundException {
+ return getDrawable(id, null);
+ }
+
+ @Override
+ public Drawable getDrawable(int id, Theme theme) {
Pair<String, ResourceValue> value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 446d139..cfe7525 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -58,7 +58,7 @@
public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
boolean platformFile) {
- super(null, null, null, 0);
+ super(resources, null, null, 0);
mBridgeResources = resources;
mContext = context;
mPlatformFile = platformFile;
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
new file mode 100644
index 0000000..112250d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Delegate.java
@@ -0,0 +1,37 @@
+/*
+ * 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.content.res;
+
+import java.util.Locale;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Resources}
+ *
+ * Through the layoutlib_create tool, the original methods of Resources have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Resources_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static String localeToLanguageTag(Resources res, Locale locale) {
+ return ULocale.forLocale(locale).toLanguageTag();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 1cc8ea5..bb05d45 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -344,7 +344,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayer(long nativeCanvas, RectF bounds,
+ /*package*/ static int native_saveLayer(long nativeCanvas, RectF bounds,
long paint, int layerFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -361,7 +361,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayer(long nativeCanvas, float l,
+ /*package*/ static int native_saveLayer(long nativeCanvas, float l,
float t, float r, float b,
long paint, int layerFlags) {
// get the delegate from the native int.
@@ -380,7 +380,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayerAlpha(long nativeCanvas,
+ /*package*/ static int native_saveLayerAlpha(long nativeCanvas,
RectF bounds, int alpha,
int layerFlags) {
// get the delegate from the native int.
@@ -393,7 +393,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_saveLayerAlpha(long nativeCanvas, float l,
+ /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
// get the delegate from the native int.
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index 38174f1..bf03a5e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -56,7 +56,7 @@
// ---- native methods ----
@LayoutlibDelegate
- /*package*/ static void destroyFilter(long native_instance, long nativeColorFilter) {
+ /*package*/ static void destroyFilter(long native_instance) {
sManager.removeJavaReferenceFor(native_instance);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
index ca8f450..9aac2bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -60,11 +60,5 @@
return sManager.addNewDelegate(newDelegate);
}
- @LayoutlibDelegate
- /*package*/ static long nColorMatrixFilter(long nativeFilter, float[] array) {
- // pass
- return 0;
- }
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
index defaac3..501d55c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -60,11 +60,5 @@
return sManager.addNewDelegate(newDelegate);
}
- @LayoutlibDelegate
- /*package*/ static int nCreateLightingFilter(long nativeFilter, int mul, int add) {
- // pass
- return 0;
- }
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 7007b71..de2e592 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -688,7 +688,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getStyle(long native_object) {
+ /*package*/ static int native_getStyle(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -710,7 +710,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getStrokeCap(long native_object) {
+ /*package*/ static int native_getStrokeCap(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -732,7 +732,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getStrokeJoin(long native_object) {
+ /*package*/ static int native_getStrokeJoin(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -889,7 +889,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getTextAlign(long native_object) {
+ /*package*/ static int native_getTextAlign(long native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
if (delegate == null) {
@@ -922,7 +922,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getTextWidths(long native_object, char[] text, int index,
+ /*package*/ static int native_getTextWidths(long native_object, char[] text, int index,
int count, int bidiFlags, float[] widths) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -964,14 +964,14 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getTextWidths(long native_object, String text, int start,
+ /*package*/ static int native_getTextWidths(long native_object, String text, int start,
int end, int bidiFlags, float[] widths) {
return native_getTextWidths(native_object, text.toCharArray(), start, end - start,
bidiFlags, widths);
}
@LayoutlibDelegate
- /* package */static long native_getTextGlyphs(long native_object, String text, int start,
+ /* package */static int native_getTextGlyphs(long native_object, String text, int start,
int end, int contextStart, int contextEnd, int flags, char[] glyphs) {
// FIXME
return 0;
@@ -1012,7 +1012,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getTextRunCursor(Paint thisPaint, long native_object, char[] text,
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -1021,7 +1021,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getTextRunCursor(Paint thisPaint, long native_object, String text,
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, long native_object, String text,
int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
// FIXME
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index 49f314c..6666385 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -142,7 +142,7 @@
}
@LayoutlibDelegate
- /*package*/ static long native_getFillType(long nPath) {
+ /*package*/ static int native_getFillType(long nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
return 0;
@@ -490,20 +490,6 @@
return new float[0];
}
- @LayoutlibDelegate
- /*package*/ static long native_trim(long nPath, long nTargetPath, long nPathMeasure,
- float trimStart, float trimEnd, float trimOffset) {
- // TODO: add trim.
- Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.trim() not supported", null);
- return nPathMeasure;
-
- }
-
- @LayoutlibDelegate
- private static void native_destroyMeasure(long nPathMeasure) {
- // Do nothing.
- }
-
// ---- Private helper methods ----
private void set(Path_Delegate delegate) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 6049919..1bc3033 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -60,12 +60,5 @@
return sManager.addNewDelegate(newDelegate);
}
- @LayoutlibDelegate
- /*package*/ static long nCreatePorterDuffFilter(long nativeFilter, int srcColor,
- int porterDuffMode) {
- // pass
- return 0;
- }
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
index ea23649..edb7025 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -275,21 +275,20 @@
}
@LayoutlibDelegate
- /*package*/ static boolean nativeSetRegion(long native_dst, long native_src) {
+ /*package*/ static void nativeSetRegion(long native_dst, long native_src) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
- return true;
+ return;
}
Region_Delegate srcRegion = sManager.getDelegate(native_src);
if (srcRegion == null) {
- return true;
+ return;
}
dstRegion.mArea.reset();
dstRegion.mArea.add(srcRegion.mArea);
- return true;
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index a25fb59..60cd157 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -103,6 +103,9 @@
if (familyName == null) {
familyName = DEFAULT_FAMILY;
}
+ if (style < 0) {
+ style = Typeface.NORMAL;
+ }
Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style);
if (sFontLoader != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
index 108b651..cc7338a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
@@ -57,7 +57,9 @@
private static final String FONT_SUFFIX_NONE = ".ttf";
private static final String FONT_SUFFIX_REGULAR = "-Regular.ttf";
private static final String FONT_SUFFIX_BOLD = "-Bold.ttf";
- private static final String FONT_SUFFIX_ITALIC = "-Italic.ttf";
+ // FONT_SUFFIX_ITALIC will always match FONT_SUFFIX_BOLDITALIC and hence it must be checked
+ // separately.
+ private static final String FONT_SUFFIX_ITALIC = "Italic.ttf";
private static final String FONT_SUFFIX_BOLDITALIC = "-BoldItalic.ttf";
// This must match the values of Typeface styles so that we can use them for indices in this
@@ -285,10 +287,10 @@
mFontInfo.font[Typeface.NORMAL] = font;
} else if (fileName.endsWith(FONT_SUFFIX_BOLD)) {
mFontInfo.font[Typeface.BOLD] = font;
- } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) {
- mFontInfo.font[Typeface.ITALIC] = font;
} else if (fileName.endsWith(FONT_SUFFIX_BOLDITALIC)) {
mFontInfo.font[Typeface.BOLD_ITALIC] = font;
+ } else if (fileName.endsWith(FONT_SUFFIX_ITALIC)) {
+ mFontInfo.font[Typeface.ITALIC] = font;
} else if (fileName.endsWith(FONT_SUFFIX_NONE)) {
mFontInfo.font[Typeface.NORMAL] = font;
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
index d3218db..274516c 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -121,6 +121,15 @@
Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(),
parameters);
+ // check the return type of the methods match.
+ assertTrue(
+ String.format("Delegate method %1$s.%2$s does not match the corresponding " +
+ "framework method which returns %3$s",
+ delegateClass.getName(),
+ getMethodName(delegateMethod),
+ originalMethod.getReturnType().getName()),
+ delegateMethod.getReturnType() == originalMethod.getReturnType());
+
// check that the method has the annotation
assertNotNull(
String.format(
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 79aa642..4236038 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -125,6 +125,7 @@
"android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
"android.content.res.Resources$Theme#obtainStyledAttributes",
"android.content.res.Resources$Theme#resolveAttribute",
+ "android.content.res.Resources#localeToLanguageTag",
"android.content.res.TypedArray#getValueAt",
"android.graphics.BitmapFactory#finishDecode",
"android.os.Handler#sendMessageAtTime",