diff options
297 files changed, 8335 insertions, 3949 deletions
@@ -616,6 +616,7 @@ LOCAL_DROIDDOC_OPTIONS:=\ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_stubs_current_intermediates/src \ -api $(INTERNAL_PLATFORM_API_FILE) \ + -removedApi $(INTERNAL_PLATFORM_REMOVED_API_FILE) \ -nodocs LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk diff --git a/api/current.txt b/api/current.txt index 9df5c9e..23229d4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -314,6 +314,7 @@ package android { field public static final int backgroundSplit = 16843659; // 0x101038b field public static final int backgroundStacked = 16843658; // 0x101038a field public static final int backupAgent = 16843391; // 0x101027f + field public static final int banner = 16843762; // 0x10103f2 field public static final int baseline = 16843548; // 0x101031c field public static final int baselineAlignBottom = 16843042; // 0x1010122 field public static final int baselineAligned = 16843046; // 0x1010126 @@ -345,7 +346,7 @@ package android { 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 = 16843774; // 0x10103fe + field public static final int castsShadow = 16843775; // 0x10103ff field public static final int category = 16843752; // 0x10103e8 field public static final int centerBright = 16842956; // 0x10100cc field public static final int centerColor = 16843275; // 0x101020b @@ -399,10 +400,10 @@ package android { field public static final int content = 16843355; // 0x101025b field public static final int contentAuthority = 16843408; // 0x1010290 field public static final int contentDescription = 16843379; // 0x1010273 - field public static final int controlX1 = 16843768; // 0x10103f8 - field public static final int controlX2 = 16843770; // 0x10103fa - field public static final int controlY1 = 16843769; // 0x10103f9 - field public static final int controlY2 = 16843771; // 0x10103fb + 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 @@ -505,7 +506,7 @@ package android { field public static final int fastScrollOverlayPosition = 16843578; // 0x101033a field public static final int fastScrollPreviewBackgroundLeft = 16843575; // 0x1010337 field public static final int fastScrollPreviewBackgroundRight = 16843576; // 0x1010338 - field public static final int fastScrollStyle = 16843763; // 0x10103f3 + field public static final int fastScrollStyle = 16843764; // 0x10103f4 field public static final int fastScrollTextColor = 16843609; // 0x1010359 field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336 field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339 @@ -531,7 +532,7 @@ package android { field public static final int format12Hour = 16843722; // 0x10103ca field public static final int format24Hour = 16843723; // 0x10103cb field public static final int fragment = 16843491; // 0x10102e3 - field public static final int fragmentBreadCrumbsStyle = 16843762; // 0x10103f2 + field public static final int fragmentBreadCrumbsStyle = 16843763; // 0x10103f3 field public static final int fragmentCloseEnterAnimation = 16843495; // 0x10102e7 field public static final int fragmentCloseExitAnimation = 16843496; // 0x10102e8 field public static final int fragmentFadeEnterAnimation = 16843497; // 0x10102e9 @@ -825,7 +826,7 @@ package android { field public static final int persistent = 16842765; // 0x101000d field public static final int persistentDrawingCache = 16842990; // 0x10100ee field public static final deprecated int phoneNumber = 16843111; // 0x1010167 - field public static final int pinned = 16843776; // 0x1010400 + field public static final int pinned = 16843777; // 0x1010401 field public static final int pivotX = 16843189; // 0x10101b5 field public static final int pivotY = 16843190; // 0x10101b6 field public static final int popupAnimationStyle = 16843465; // 0x10102c9 @@ -889,7 +890,7 @@ package android { field public static final int required = 16843406; // 0x101028e field public static final int requiredAccountType = 16843734; // 0x10103d6 field public static final int requiredForAllUsers = 16843728; // 0x10103d0 - field public static final int requiredForProfile = 16843775; // 0x10103ff + field public static final int requiredForProfile = 16843776; // 0x1010400 field public static final int requiresFadingEdge = 16843685; // 0x10103a5 field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364 field public static final int resizeMode = 16843619; // 0x1010363 @@ -960,7 +961,7 @@ package android { 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 = 16843772; // 0x10103fc + field public static final int sharedElementName = 16843773; // 0x10103fd field public static final int sharedUserId = 16842763; // 0x101000b field public static final int sharedUserLabel = 16843361; // 0x1010261 field public static final int shouldDisableView = 16843246; // 0x10101ee @@ -1137,7 +1138,7 @@ package android { field public static final int tileMode = 16843265; // 0x1010201 field public static final int timeZone = 16843724; // 0x10103cc field public static final int tint = 16843041; // 0x1010121 - field public static final int tintMode = 16843767; // 0x10103f7 + field public static final int tintMode = 16843768; // 0x10103f8 field public static final int title = 16843233; // 0x10101e1 field public static final int titleCondensed = 16843234; // 0x10101e2 field public static final int titleTextStyle = 16843512; // 0x10102f8 @@ -1159,11 +1160,11 @@ package android { field public static final int transformPivotX = 16843552; // 0x1010320 field public static final int transformPivotY = 16843553; // 0x1010321 field public static final int transition = 16843743; // 0x10103df - field public static final int transitionGroup = 16843773; // 0x10103fd + field public static final int transitionGroup = 16843774; // 0x10103fe field public static final int transitionOrdering = 16843744; // 0x10103e0 field public static final int translationX = 16843554; // 0x1010322 field public static final int translationY = 16843555; // 0x1010323 - field public static final int translationZ = 16843766; // 0x10103f6 + field public static final int translationZ = 16843767; // 0x10103f7 field public static final int type = 16843169; // 0x10101a1 field public static final int typeface = 16842902; // 0x1010096 field public static final int uiOptions = 16843672; // 0x1010398 @@ -1220,8 +1221,8 @@ package android { field public static final int windowBackground = 16842836; // 0x1010054 field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b field public static final int windowContentOverlay = 16842841; // 0x1010059 - field public static final int windowContentTransitionManager = 16843765; // 0x10103f5 - field public static final int windowContentTransitions = 16843764; // 0x10103f4 + field public static final int windowContentTransitionManager = 16843766; // 0x10103f6 + field public static final int windowContentTransitions = 16843765; // 0x10103f5 field public static final int windowDisablePreview = 16843298; // 0x1010222 field public static final int windowEnableSplitTouch = 16843543; // 0x1010317 field public static final int windowEnterAnimation = 16842932; // 0x10100b4 @@ -4796,7 +4797,7 @@ package android.app.admin { method public int setStorageEncryption(android.content.ComponentName, boolean); method public void wipeData(int); field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN"; - field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.managedprovisioning.ACTION_PROVISION_MANAGED_PROFILE"; + field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE"; field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD"; field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION"; field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2 @@ -6848,6 +6849,7 @@ package android.content { field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000 field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000 field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000 + field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 268959744; // 0x10080000 field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000 field public static final int FLAG_ACTIVITY_NO_ANIMATION = 65536; // 0x10000 field public static final int FLAG_ACTIVITY_NO_HISTORY = 1073741824; // 0x40000000 @@ -7417,6 +7419,7 @@ package android.content.pm { ctor public ComponentInfo(); ctor public ComponentInfo(android.content.pm.ComponentInfo); ctor protected ComponentInfo(android.os.Parcel); + method public final int getBannerResource(); method public final int getIconResource(); method public final int getLogoResource(); method public boolean isEnabled(); @@ -7520,11 +7523,13 @@ package android.content.pm { ctor protected PackageItemInfo(android.os.Parcel); method protected void dumpBack(android.util.Printer, java.lang.String); method protected void dumpFront(android.util.Printer, java.lang.String); + method public android.graphics.drawable.Drawable loadBanner(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager); method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String); method public void writeToParcel(android.os.Parcel, int); + field public int banner; field public int icon; field public int labelRes; field public int logo; @@ -7552,12 +7557,16 @@ package android.content.pm { method public abstract void clearPackagePreferredActivities(java.lang.String); method public abstract java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]); method public abstract void extendVerificationTimeout(int, int, long); + method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int); + method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo); + method public abstract android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int getApplicationEnabledSetting(java.lang.String); method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo); method public abstract android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -7637,6 +7646,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen"; field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods"; + field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback"; field public static final java.lang.String FEATURE_LIVE_WALLPAPER = "android.software.live_wallpaper"; field public static final java.lang.String FEATURE_LOCATION = "android.hardware.location"; field public static final java.lang.String FEATURE_LOCATION_GPS = "android.hardware.location.gps"; @@ -7660,7 +7670,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_TELEPHONY = "android.hardware.telephony"; field public static final java.lang.String FEATURE_TELEPHONY_CDMA = "android.hardware.telephony.cdma"; field public static final java.lang.String FEATURE_TELEPHONY_GSM = "android.hardware.telephony.gsm"; - field public static final java.lang.String FEATURE_TELEVISION = "android.hardware.type.television"; + field public static final deprecated java.lang.String FEATURE_TELEVISION = "android.hardware.type.television"; field public static final java.lang.String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen"; field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch"; field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct"; @@ -11286,6 +11296,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_AWB_AVAILABLE_MODES; field public static final android.hardware.camera2.CameraMetadata.Key CONTROL_MAX_REGIONS; field public static final android.hardware.camera2.CameraMetadata.Key FLASH_INFO_AVAILABLE; + field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; field public static final android.hardware.camera2.CameraMetadata.Key INFO_SUPPORTED_HARDWARE_LEVEL; field public static final android.hardware.camera2.CameraMetadata.Key JPEG_AVAILABLE_THUMBNAIL_SIZES; field public static final android.hardware.camera2.CameraMetadata.Key LENS_FACING; @@ -11326,6 +11337,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_ORIENTATION; field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_PROFILE_HUE_SAT_MAP_DIMENSIONS; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; + field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_INFO_MAX_FACE_COUNT; field public static final android.hardware.camera2.CameraMetadata.Key SYNC_MAX_LATENCY; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_MAX_CURVE_POINTS; @@ -11620,6 +11632,7 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key SENSOR_TEST_PATTERN_MODE; field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP_MODE; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_GREEN; @@ -11657,7 +11670,6 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key EDGE_MODE; field public static final android.hardware.camera2.CameraMetadata.Key FLASH_MODE; field public static final android.hardware.camera2.CameraMetadata.Key FLASH_STATE; - field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MAP; field public static final android.hardware.camera2.CameraMetadata.Key HOT_PIXEL_MODE; field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_COORDINATES; field public static final android.hardware.camera2.CameraMetadata.Key JPEG_GPS_PROCESSING_METHOD; @@ -11694,6 +11706,8 @@ package android.hardware.camera2 { field public static final android.hardware.camera2.CameraMetadata.Key SHADING_MODE; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACES; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP; + field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_HOT_PIXEL_MAP_MODE; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_LENS_SHADING_MAP; field public static final android.hardware.camera2.CameraMetadata.Key STATISTICS_SCENE_FLICKER; field public static final android.hardware.camera2.CameraMetadata.Key TONEMAP_CURVE_BLUE; @@ -13816,6 +13830,7 @@ package android.media { field public static final int RATING_4_STARS = 4; // 0x4 field public static final int RATING_5_STARS = 5; // 0x5 field public static final int RATING_HEART = 1; // 0x1 + field public static final int RATING_NONE = 0; // 0x0 field public static final int RATING_PERCENTAGE = 6; // 0x6 field public static final int RATING_THUMB_UP_DOWN = 2; // 0x2 } @@ -14456,34 +14471,76 @@ package android.media.effect { package android.media.session { public final class MediaController { - ctor public MediaController(android.media.session.MediaSessionToken); method public void addCallback(android.media.session.MediaController.Callback); method public void addCallback(android.media.session.MediaController.Callback, android.os.Handler); + method public static android.media.session.MediaController fromToken(android.media.session.MediaSessionToken); + method public android.media.session.TransportController getTransportController(); method public void removeCallback(android.media.session.MediaController.Callback); - method public void sendCommand(java.lang.String, android.os.Bundle); + method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); 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 MediaMetadata implements android.os.Parcelable { + method public int describeContents(); + method public android.graphics.Bitmap getBitmap(java.lang.String); + method public long getLong(java.lang.String); + method public android.media.Rating getRating(java.lang.String); + method public java.lang.String getString(java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"; + field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"; + field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"; + field public static final java.lang.String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"; + field public static final java.lang.String METADATA_KEY_ART = "android.media.metadata.ART"; + field public static final java.lang.String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"; + field public static final java.lang.String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"; + field public static final java.lang.String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"; + field public static final java.lang.String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"; + field public static final java.lang.String METADATA_KEY_DATE = "android.media.metadata.DATE"; + field public static final java.lang.String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"; + field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION"; + field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE"; + field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"; + field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING"; + field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE"; + field public static final java.lang.String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"; + field public static final java.lang.String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"; + field public static final java.lang.String METADATA_KEY_WRITER = "android.media.metadata.WRITER"; + field public static final java.lang.String METADATA_KEY_YEAR = "android.media.metadata.YEAR"; + } + + public static final class MediaMetadata.Builder { + ctor public MediaMetadata.Builder(); + ctor public MediaMetadata.Builder(android.media.session.MediaMetadata); + method public android.media.session.MediaMetadata build(); + method public android.media.session.MediaMetadata.Builder putBitmap(java.lang.String, android.graphics.Bitmap); + method public android.media.session.MediaMetadata.Builder putLong(java.lang.String, long); + method public android.media.session.MediaMetadata.Builder putRating(java.lang.String, android.media.Rating); + method public android.media.session.MediaMetadata.Builder putString(java.lang.String, java.lang.String); + } + public final class MediaSession { method public void addCallback(android.media.session.MediaSession.Callback); method public void addCallback(android.media.session.MediaSession.Callback, android.os.Handler); method public android.media.session.MediaSessionToken getSessionToken(); + method public android.media.session.TransportPerformer getTransportPerformer(); + method public void publish(); method public void release(); method public void removeCallback(android.media.session.MediaSession.Callback); - method public void setPlaybackState(int); + method public void sendEvent(java.lang.String, android.os.Bundle); + method public android.media.session.TransportPerformer setTransportPerformerEnabled(); } public static abstract class MediaSession.Callback { ctor public MediaSession.Callback(); - method public void onCommand(java.lang.String, android.os.Bundle); + method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); method public void onMediaButton(android.content.Intent); method public void onRequestRouteChange(android.os.Bundle); } @@ -14499,6 +14556,137 @@ package android.media.session { field public static final android.os.Parcelable.Creator CREATOR; } + public final class PlaybackState implements android.os.Parcelable { + ctor public PlaybackState(); + ctor public PlaybackState(android.media.session.PlaybackState); + method public int describeContents(); + method public long getActions(); + method public long getBufferPosition(); + method public java.lang.String getErrorMessage(); + method public long getPosition(); + method public float getSpeed(); + method public int getState(); + method public void setActions(long); + method public void setBufferPosition(long); + method public void setErrorMessage(java.lang.String); + method public void setPosition(long); + method public void setSpeed(float); + method public void setState(int); + method public void writeToParcel(android.os.Parcel, int); + field public static final long ACTION_FASTFORWARD = 64L; // 0x40L + field public static final long ACTION_NEXT_ITEM = 32L; // 0x20L + field public static final long ACTION_PAUSE = 2L; // 0x2L + field public static final long ACTION_PLAY = 4L; // 0x4L + field public static final long ACTION_PREVIOUS_ITEM = 16L; // 0x10L + field public static final long ACTION_RATING = 128L; // 0x80L + field public static final long ACTION_REWIND = 8L; // 0x8L + field public static final long ACTION_SEEK_TO = 256L; // 0x100L + field public static final long ACTION_STOP = 1L; // 0x1L + field public static final android.os.Parcelable.Creator CREATOR; + field public static final int PLAYSTATE_BUFFERING = 6; // 0x6 + field public static final int PLAYSTATE_ERROR = 7; // 0x7 + field public static final int PLAYSTATE_FAST_FORWARDING = 4; // 0x4 + field public static final int PLAYSTATE_NONE = 0; // 0x0 + field public static final int PLAYSTATE_PAUSED = 2; // 0x2 + field public static final int PLAYSTATE_PLAYING = 3; // 0x3 + field public static final int PLAYSTATE_REWINDING = 5; // 0x5 + field public static final int PLAYSTATE_STOPPED = 1; // 0x1 + } + + public final class RouteInterface { + method public void addListener(android.media.session.RouteInterface.EventListener); + method public void addListener(android.media.session.RouteInterface.EventListener, android.os.Handler); + method public void removeListener(android.media.session.RouteInterface.EventListener); + method public void sendCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); + } + + public static abstract class RouteInterface.EventListener { + ctor public RouteInterface.EventListener(); + method public abstract void onEvent(java.lang.String, android.os.Bundle); + } + + public static abstract class RouteInterface.Stub { + ctor public RouteInterface.Stub(); + method public abstract java.lang.String getName(); + method public abstract void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); + method public final void sendEvent(android.media.session.MediaSession, java.lang.String, android.os.Bundle); + } + + public final class RouteTransportControls { + method public void addListener(android.media.session.RouteTransportControls.Listener); + method public void addListener(android.media.session.RouteTransportControls.Listener, android.os.Handler); + method public void fastForward(float); + method public static android.media.session.RouteTransportControls from(android.media.session.MediaController); + method public void getCapabilities(android.os.ResultReceiver); + method public void getCurrentPosition(android.os.ResultReceiver); + method public void pause(); + method public void play(); + method public void removeListener(android.media.session.RouteTransportControls.Listener); + field public static final java.lang.String NAME = "android.media.session.RouteTransportControls"; + } + + public static abstract class RouteTransportControls.Listener { + ctor public RouteTransportControls.Listener(); + method public void onMetadataUpdate(android.os.Bundle); + method public void onPlaybackStateChange(int); + } + + public static abstract class RouteTransportControls.Stub extends android.media.session.RouteInterface.Stub { + ctor public RouteTransportControls.Stub(android.media.session.MediaSession); + method public void fastForward(float); + method public long getCapabilities(); + method public long getCurrentPosition(); + method public java.lang.String getName(); + method public void onCommand(java.lang.String, android.os.Bundle, android.os.ResultReceiver); + method public final void updatePlaybackState(int); + } + + public final class TransportController { + method public void addStateListener(android.media.session.TransportController.TransportStateListener); + method public void addStateListener(android.media.session.TransportController.TransportStateListener, android.os.Handler); + method public void fastForward(); + method public android.media.session.MediaMetadata getMetadata(); + method public android.media.session.PlaybackState getPlaybackState(); + method public int getRatingType(); + method public void next(); + method public void pause(); + method public void play(); + method public void previous(); + method public void rate(android.media.Rating); + method public void removeStateListener(android.media.session.TransportController.TransportStateListener); + method public void rewind(); + method public void seekTo(long); + method public void stop(); + } + + public static abstract class TransportController.TransportStateListener { + ctor public TransportController.TransportStateListener(); + method public void onMetadataChanged(android.media.session.MediaMetadata); + method public void onPlaybackStateChanged(android.media.session.PlaybackState); + } + + public final class TransportPerformer { + method public void addListener(android.media.session.TransportPerformer.Listener); + method public void addListener(android.media.session.TransportPerformer.Listener, android.os.Handler); + method public void removeListener(android.media.session.TransportPerformer.Listener); + method public final void setMetadata(android.media.session.MediaMetadata); + method public final void setPlaybackState(android.media.session.PlaybackState); + } + + public static abstract class TransportPerformer.Listener { + ctor public TransportPerformer.Listener(); + method public void onFastForward(); + method public void onNext(); + method public void onPause(); + method public void onPlay(); + method public void onPrevious(); + method public void onRate(android.media.Rating); + method public void onRewind(); + method public void onRouteFocusChange(int); + method public void onSeekTo(long); + method public void onStop(); + } + } package android.mtp { @@ -25300,12 +25488,16 @@ package android.test.mock { method public void clearPackagePreferredActivities(java.lang.String); method public java.lang.String[] currentToCanonicalPackageNames(java.lang.String[]); method public void extendVerificationTimeout(int, int, long); + method public android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; + method public android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException; method public android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; method public android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException; method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int); + method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo); + method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int getApplicationEnabledSetting(java.lang.String); method public android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo); method public android.graphics.drawable.Drawable getApplicationIcon(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; diff --git a/api/removed.txt b/api/removed.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/api/removed.txt diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 01e7615..92cb52c 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -114,6 +114,8 @@ public class Am extends BaseCommand { " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" + " am stack list\n" + " am stack info <STACK_ID>\n" + + " am lock-task <TASK_ID>\n" + + " am lock-task stop\n" + "\n" + "am start: start an Activity. Options are:\n" + " -D: enable debugging\n" + @@ -218,6 +220,8 @@ public class Am extends BaseCommand { "\n" + "am stack info: display the information about activity stack <STACK_ID>.\n" + "\n" + + "am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" + + "\n" + "<INTENT> specifications include these flags and arguments:\n" + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + @@ -309,6 +313,8 @@ public class Am extends BaseCommand { runStopUser(); } else if (op.equals("stack")) { runStack(); + } else if (op.equals("lock-task")) { + runLockTask(); } else { showError("Error: unknown command '" + op + "'"); } @@ -1641,4 +1647,19 @@ public class Am extends BaseCommand { } catch (RemoteException e) { } } + + private void runLockTask() throws Exception { + String taskIdStr = nextArgRequired(); + try { + if (taskIdStr.equals("stop")) { + mAm.stopLockTaskMode(); + } else { + int taskId = Integer.valueOf(taskIdStr); + mAm.startLockTaskMode(taskId); + } + System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") + + "in lockTaskMode"); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 287c463..606d803 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -5606,6 +5606,22 @@ public class Activity extends ContextThemeWrapper } } + /** @hide */ + public void startLockTask() { + try { + ActivityManagerNative.getDefault().startLockTaskMode(mToken); + } catch (RemoteException e) { + } + } + + /** @hide */ + public void stopLockTask() { + try { + ActivityManagerNative.getDefault().stopLockTaskMode(); + } catch (RemoteException e) { + } + } + /** * Interface for informing a translucent {@link Activity} once all visible activities below it * have completed drawing. This is necessary only after an {@link Activity} has been made diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 7f7616f..a2183e6 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -155,6 +155,13 @@ public class ActivityManager { public static final int START_SWITCHES_CANCELED = 4; /** + * Result for IActivityManaqer.startActivity: a new activity was attempted to be started + * while in Lock Task Mode. + * @hide + */ + public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION = 5; + + /** * Flag for IActivityManaqer.startActivity: do special start mode where * a new activity is launched only if it is needed. * @hide @@ -2232,4 +2239,35 @@ public class ActivityManager { e.printStackTrace(pw); } } + + /** + * @hide + */ + public void startLockTaskMode(int taskId) { + try { + ActivityManagerNative.getDefault().startLockTaskMode(taskId); + } catch (RemoteException e) { + } + } + + /** + * @hide + */ + public void stopLockTaskMode() { + try { + ActivityManagerNative.getDefault().stopLockTaskMode(); + } catch (RemoteException e) { + } + } + + /** + * @hide + */ + public boolean isInLockTaskMode() { + try { + return ActivityManagerNative.getDefault().isInLockTaskMode(); + } catch (RemoteException e) { + return false; + } + } } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index c7c81dd..373a8a3 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -2097,6 +2097,37 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeStrongBinder(homeActivityToken); return true; } + + case START_LOCK_TASK_BY_TASK_ID_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final int taskId = data.readInt(); + startLockTaskMode(taskId); + reply.writeNoException(); + return true; + } + + case START_LOCK_TASK_BY_TOKEN_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + IBinder token = data.readStrongBinder(); + startLockTaskMode(token); + reply.writeNoException(); + return true; + } + + case STOP_LOCK_TASK_MODE_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + stopLockTaskMode(); + reply.writeNoException(); + return true; + } + + case IS_IN_LOCK_TASK_MODE_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final boolean isInLockTaskMode = isInLockTaskMode(); + reply.writeNoException(); + reply.writeInt(isInLockTaskMode ? 1 : 0); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -4820,5 +4851,53 @@ class ActivityManagerProxy implements IActivityManager return res; } + @Override + public void startLockTaskMode(int taskId) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(taskId); + mRemote.transact(START_LOCK_TASK_BY_TASK_ID_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + @Override + public void startLockTaskMode(IBinder token) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeStrongBinder(token); + mRemote.transact(START_LOCK_TASK_BY_TOKEN_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + @Override + public void stopLockTaskMode() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(STOP_LOCK_TASK_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + @Override + public boolean isInLockTaskMode() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(IS_IN_LOCK_TASK_MODE_TRANSACTION, data, reply, 0); + reply.readException(); + boolean isInLockTaskMode = reply.readInt() == 1; + data.recycle(); + reply.recycle(); + return isInLockTaskMode; + } + private IBinder mRemote; } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index e71d47d..079cf7a 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -878,7 +878,7 @@ public class AppOpsManager { } /** - * Like {@link #checkOp but instead of throwing a {@link SecurityException} it + * Like {@link #checkOp} but instead of throwing a {@link SecurityException} it * returns {@link #MODE_ERRORED}. */ public int checkOpNoThrow(String op, int uid, String packageName) { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 061e5a5..8165fa1 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -727,6 +727,39 @@ final class ApplicationPackageManager extends PackageManager { } @Override + public Drawable getActivityBanner(ComponentName activityName) + throws NameNotFoundException { + return getActivityInfo(activityName, 0).loadBanner(this); + } + + @Override + public Drawable getActivityBanner(Intent intent) + throws NameNotFoundException { + if (intent.getComponent() != null) { + return getActivityBanner(intent.getComponent()); + } + + ResolveInfo info = resolveActivity( + intent, PackageManager.MATCH_DEFAULT_ONLY); + if (info != null) { + return info.activityInfo.loadBanner(this); + } + + throw new NameNotFoundException(intent.toUri(0)); + } + + @Override + public Drawable getApplicationBanner(ApplicationInfo info) { + return info.loadBanner(this); + } + + @Override + public Drawable getApplicationBanner(String packageName) + throws NameNotFoundException { + return getApplicationBanner(getApplicationInfo(packageName, 0)); + } + + @Override public Drawable getActivityLogo(ComponentName activityName) throws NameNotFoundException { return getActivityInfo(activityName, 0).loadLogo(this); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index f2cabf4..cb06a42 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -424,6 +424,18 @@ public interface IActivityManager extends IInterface { public IBinder getHomeActivityToken() throws RemoteException; + /** @hide */ + public void startLockTaskMode(int taskId) throws RemoteException; + + /** @hide */ + public void startLockTaskMode(IBinder token) throws RemoteException; + + /** @hide */ + public void stopLockTaskMode() throws RemoteException; + + /** @hide */ + public boolean isInLockTaskMode() throws RemoteException; + /* * Private non-Binder interfaces */ @@ -719,4 +731,8 @@ public interface IActivityManager extends IInterface { int GET_TAG_FOR_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+210; int START_USER_IN_BACKGROUND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+211; int IS_IN_HOME_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+212; + int START_LOCK_TASK_BY_TASK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+213; + int START_LOCK_TASK_BY_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+214; + int STOP_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+215; + int IS_IN_LOCK_TASK_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+216; } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index e06cf38..30c84f6 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -95,7 +95,7 @@ public class DevicePolicyManager { */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_PROVISION_MANAGED_PROFILE - = "android.managedprovisioning.ACTION_PROVISION_MANAGED_PROFILE"; + = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE"; /** * A String extra holding the name of the package of the mobile device management application diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 96479e2..0175d62 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3457,7 +3457,16 @@ public class Intent implements Parcelable, Cloneable { */ public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000; /** - * <strong>Do not use this flag unless you are implementing your own + * This flag is used to create a new task and launch an activity into it. + * This flag is always paired with either {@link #FLAG_ACTIVITY_NEW_DOCUMENT} + * or {@link #FLAG_ACTIVITY_NEW_TASK}. In both cases these flags alone would + * search through existing tasks for ones matching this Intent. Only if no such + * task is found would a new task be created. When paired with + * FLAG_ACTIVITY_MULTIPLE_TASK both of these behaviors are modified to skip + * the search for a matching task and unconditionally start a new task. + * + * <strong>When used with {@link #FLAG_ACTIVITY_NEW_TASK} do not use this + * flag unless you are implementing your own * top-level application launcher.</strong> Used in conjunction with * {@link #FLAG_ACTIVITY_NEW_TASK} to disable the * behavior of bringing an existing task to the foreground. When set, @@ -3469,12 +3478,18 @@ public class Intent implements Parcelable, Cloneable { * you should not use this flag unless you provide some way for a user to * return back to the tasks you have launched.</strong> * - * <p>This flag is ignored if - * {@link #FLAG_ACTIVITY_NEW_TASK} is not set. + * See {@link #FLAG_ACTIVITY_NEW_DOCUMENT} for details of this flag's use for + * creating new document tasks. + * + * <p>This flag is ignored if one of {@link #FLAG_ACTIVITY_NEW_TASK} or + * {@link #FLAG_ACTIVITY_NEW_TASK} is not also set. * * <p>See * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back * Stack</a> for more information about tasks. + * + * @see #FLAG_ACTIVITY_NEW_DOCUMENT + * @see #FLAG_ACTIVITY_NEW_TASK */ public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000; /** @@ -3581,6 +3596,34 @@ public class Intent implements Parcelable, Cloneable { */ public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000; /** + * This flag is used to break out "documents" into separate tasks that can + * be reached via the Recents mechanism. Such a document is any kind of + * item for which an application may want to maintain multiple simultaneous + * instances. Examples might be text files, web pages, spreadsheets, or + * emails. Each such document will be in a separate task in the Recents list. + * + * <p>When set, the activity specified by this Intent will launch into a + * separate task rooted at that activity. The activity launched must be + * defined with {@link android.R.attr#launchMode} "standard" or "singleTop". + * + * <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without + * {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will + * search for an existing task with a matching target activity and Intent + * data URI and relaunch that task, first finishing all activities down to + * the root activity and then calling the root activity's + * {@link android.app.Activity#onNewIntent(Intent)} method. If no existing + * task's root activity matches the Intent's data URI then a new task will + * be launched with the target activity as root. + * + * <p>When paired with {@link #FLAG_ACTIVITY_MULTIPLE_TASK} this will + * always create a new task. Thus the same document may be made to appear + * more than one time in Recents. + * + * @see #FLAG_ACTIVITY_MULTIPLE_TASK + */ + public static final int FLAG_ACTIVITY_NEW_DOCUMENT = + FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_TASK; + /** * If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaveHint} * callback from occurring on the current frontmost activity before it is * paused as the newly-started activity is brought to the front. @@ -6246,6 +6289,7 @@ public class Intent implements Parcelable, Cloneable { * @see #FLAG_ACTIVITY_FORWARD_RESULT * @see #FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY * @see #FLAG_ACTIVITY_MULTIPLE_TASK + * @see #FLAG_ACTIVITY_NEW_DOCUMENT * @see #FLAG_ACTIVITY_NEW_TASK * @see #FLAG_ACTIVITY_NO_ANIMATION * @see #FLAG_ACTIVITY_NO_HISTORY @@ -7342,4 +7386,9 @@ public class Intent implements Parcelable, Cloneable { String htmlText = htmlTexts != null ? htmlTexts.get(which) : null; return new ClipData.Item(text, htmlText, null, uri); } + + /** @hide */ + public boolean isDocument() { + return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT; + } } diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java index 4dbcf23..7e8f285 100644 --- a/core/java/android/content/pm/ComponentInfo.java +++ b/core/java/android/content/pm/ComponentInfo.java @@ -128,6 +128,17 @@ public class ComponentInfo extends PackageItemInfo { return logo != 0 ? logo : applicationInfo.logo; } + /** + * Return the banner resource identifier to use for this component. If the + * component defines a banner, that is used; else, the application banner is + * used. + * + * @return The banner associated with this component. + */ + public final int getBannerResource() { + return banner != 0 ? banner : applicationInfo.banner; + } + protected void dumpFront(Printer pw, String prefix) { super.dumpFront(pw, prefix); pw.println(prefix + "enabled=" + enabled + " exported=" + exported @@ -175,6 +186,13 @@ public class ComponentInfo extends PackageItemInfo { /** * @hide */ + @Override protected Drawable loadDefaultBanner(PackageManager pm) { + return applicationInfo.loadBanner(pm); + } + + /** + * @hide + */ @Override protected Drawable loadDefaultLogo(PackageManager pm) { return applicationInfo.loadLogo(pm); diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index a67326e..58f1c84 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -68,6 +68,12 @@ public class PackageItemInfo { /** * A drawable resource identifier (in the package's resources) of this + * component's banner. From the "banner" attribute or, if not set, 0. + */ + public int banner; + + /** + * A drawable resource identifier (in the package's resources) of this * component's logo. Logos may be larger/wider than icons and are * displayed by certain UI elements in place of a name or name/icon * combination. From the "logo" attribute or, if not set, 0. @@ -92,6 +98,7 @@ public class PackageItemInfo { nonLocalizedLabel = orig.nonLocalizedLabel; if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim(); icon = orig.icon; + banner = orig.banner; logo = orig.logo; metaData = orig.metaData; } @@ -146,6 +153,27 @@ public class PackageItemInfo { } /** + * Retrieve the current graphical banner associated with this item. This + * will call back on the given PackageManager to load the banner from + * the application. + * + * @param pm A PackageManager from which the banner can be loaded; usually + * the PackageManager from which you originally retrieved this item. + * + * @return Returns a Drawable containing the item's banner. If the item + * does not have a banner, this method will return null. + */ + public Drawable loadBanner(PackageManager pm) { + if (banner != 0) { + Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo()); + if (dr != null) { + return dr; + } + } + return loadDefaultBanner(pm); + } + + /** * Retrieve the default graphical icon associated with this item. * * @param pm A PackageManager from which the icon can be loaded; usually @@ -159,7 +187,22 @@ public class PackageItemInfo { protected Drawable loadDefaultIcon(PackageManager pm) { return pm.getDefaultActivityIcon(); } - + + /** + * Retrieve the default graphical banner associated with this item. + * + * @param pm A PackageManager from which the banner can be loaded; usually + * the PackageManager from which you originally retrieved this item. + * + * @return Returns a Drawable containing the item's default banner + * or null if no default logo is available. + * + * @hide + */ + protected Drawable loadDefaultBanner(PackageManager pm) { + return null; + } + /** * Retrieve the current graphical logo associated with this item. This * will call back on the given PackageManager to load the logo from @@ -224,10 +267,11 @@ public class PackageItemInfo { pw.println(prefix + "name=" + name); } pw.println(prefix + "packageName=" + packageName); - if (labelRes != 0 || nonLocalizedLabel != null || icon != 0) { + if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) { pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes) + " nonLocalizedLabel=" + nonLocalizedLabel - + " icon=0x" + Integer.toHexString(icon)); + + " icon=0x" + Integer.toHexString(icon) + + " banner=0x" + Integer.toHexString(banner)); } } @@ -243,6 +287,7 @@ public class PackageItemInfo { dest.writeInt(icon); dest.writeInt(logo); dest.writeBundle(metaData); + dest.writeInt(banner); } protected PackageItemInfo(Parcel source) { @@ -254,6 +299,7 @@ public class PackageItemInfo { icon = source.readInt(); logo = source.readInt(); metaData = source.readBundle(); + banner = source.readInt(); } /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index b648930..e86833b 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1233,6 +1233,26 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device supports leanback UI. This is + * typically used in a living room television experience, but is a software + * feature unlike {@link #FEATURE_TELEVISION}. Devices running with this + * feature will use resources associated with the "television" UI mode. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_LEANBACK = "android.software.leanback"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device supports only leanback UI. Only + * applications designed for this experience should be run, though this is + * not enforced by the system. + * @hide + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports WiFi (802.11) networking. */ @SdkConstant(SdkConstantType.FEATURE) @@ -1252,6 +1272,7 @@ public abstract class PackageManager { * room television experience: displayed on a big screen, where the user * is sitting far away from it, and the dominant form of input will be * something like a DPAD, not through touch or mouse. + * @deprecated use {@link #FEATURE_LEANBACK} instead. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_TELEVISION = "android.hardware.type.television"; @@ -2400,9 +2421,43 @@ public abstract class PackageManager { throws NameNotFoundException; /** + * Retrieve the banner associated with an activity. Given the full name of + * an activity, retrieves the information about it and calls + * {@link ComponentInfo#loadIcon ComponentInfo.loadIcon()} to return its + * banner. If the activity cannot be found, NameNotFoundException is thrown. + * + * @param activityName Name of the activity whose banner is to be retrieved. + * @return Returns the image of the banner, or null if the activity has no + * banner specified. + * @throws NameNotFoundException Thrown if the resources for the given + * activity could not be loaded. + * @see #getActivityBanner(Intent) + */ + public abstract Drawable getActivityBanner(ComponentName activityName) + throws NameNotFoundException; + + /** + * Retrieve the banner associated with an Intent. If intent.getClassName() + * is set, this simply returns the result of + * getActivityBanner(intent.getClassName()). Otherwise it resolves the + * intent's component and returns the banner associated with the resolved + * component. If intent.getClassName() cannot be found or the Intent cannot + * be resolved to a component, NameNotFoundException is thrown. + * + * @param intent The intent for which you would like to retrieve a banner. + * @return Returns the image of the banner, or null if the activity has no + * banner specified. + * @throws NameNotFoundException Thrown if the resources for application + * matching the given intent could not be loaded. + * @see #getActivityBanner(ComponentName) + */ + public abstract Drawable getActivityBanner(Intent intent) + throws NameNotFoundException; + + /** * Return the generic icon for an activity that is used when no specific * icon is defined. - * + * * @return Drawable Image of the icon. */ public abstract Drawable getDefaultActivityIcon(); @@ -2440,19 +2495,43 @@ public abstract class PackageManager { throws NameNotFoundException; /** - * Retrieve the logo associated with an activity. Given the full name of - * an activity, retrieves the information about it and calls - * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its logo. - * If the activity cannot be found, NameNotFoundException is thrown. + * Retrieve the banner associated with an application. * - * @param activityName Name of the activity whose logo is to be retrieved. - * - * @return Returns the image of the logo or null if the activity has no - * logo specified. + * @param info Information about application being queried. + * @return Returns the image of the banner or null if the application has no + * banner specified. + * @see #getApplicationBanner(String) + */ + public abstract Drawable getApplicationBanner(ApplicationInfo info); + + /** + * Retrieve the banner associated with an application. Given the name of the + * application's package, retrieves the information about it and calls + * getApplicationIcon() to return its banner. If the application cannot be + * found, NameNotFoundException is thrown. * + * @param packageName Name of the package whose application banner is to be + * retrieved. + * @return Returns the image of the banner or null if the application has no + * banner specified. * @throws NameNotFoundException Thrown if the resources for the given - * activity could not be loaded. + * application could not be loaded. + * @see #getApplicationBanner(ApplicationInfo) + */ + public abstract Drawable getApplicationBanner(String packageName) + throws NameNotFoundException; + + /** + * Retrieve the logo associated with an activity. Given the full name of an + * activity, retrieves the information about it and calls + * {@link ComponentInfo#loadLogo ComponentInfo.loadLogo()} to return its + * logo. If the activity cannot be found, NameNotFoundException is thrown. * + * @param activityName Name of the activity whose logo is to be retrieved. + * @return Returns the image of the logo or null if the activity has no logo + * specified. + * @throws NameNotFoundException Thrown if the resources for the given + * activity could not be loaded. * @see #getActivityLogo(Intent) */ public abstract Drawable getActivityLogo(ComponentName activityName) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index c222003..f76aada 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -167,18 +167,20 @@ public class PackageParser { final int labelRes; final int iconRes; final int logoRes; + final int bannerRes; String tag; TypedArray sa; ParsePackageItemArgs(Package _owner, String[] _outError, - int _nameRes, int _labelRes, int _iconRes, int _logoRes) { + int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) { owner = _owner; outError = _outError; nameRes = _nameRes; labelRes = _labelRes; iconRes = _iconRes; logoRes = _logoRes; + bannerRes = _bannerRes; } } @@ -190,10 +192,10 @@ public class PackageParser { int flags; ParseComponentArgs(Package _owner, String[] _outError, - int _nameRes, int _labelRes, int _iconRes, int _logoRes, + int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes, String[] _sepProcesses, int _processRes, int _descriptionRes, int _enabledRes) { - super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes); + super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes); sepProcesses = _sepProcesses; processRes = _processRes; descriptionRes = _descriptionRes; @@ -1688,7 +1690,8 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestPermissionGroup_name, com.android.internal.R.styleable.AndroidManifestPermissionGroup_label, com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon, - com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo)) { + com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo, + com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1731,7 +1734,8 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestPermission_name, com.android.internal.R.styleable.AndroidManifestPermission_label, com.android.internal.R.styleable.AndroidManifestPermission_icon, - com.android.internal.R.styleable.AndroidManifestPermission_logo)) { + com.android.internal.R.styleable.AndroidManifestPermission_logo, + com.android.internal.R.styleable.AndroidManifestPermission_banner)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1800,7 +1804,8 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestPermissionTree_name, com.android.internal.R.styleable.AndroidManifestPermissionTree_label, com.android.internal.R.styleable.AndroidManifestPermissionTree_icon, - com.android.internal.R.styleable.AndroidManifestPermissionTree_logo)) { + com.android.internal.R.styleable.AndroidManifestPermissionTree_logo, + com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) { sa.recycle(); mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; @@ -1845,7 +1850,8 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestInstrumentation_name, com.android.internal.R.styleable.AndroidManifestInstrumentation_label, com.android.internal.R.styleable.AndroidManifestInstrumentation_icon, - com.android.internal.R.styleable.AndroidManifestInstrumentation_logo); + com.android.internal.R.styleable.AndroidManifestInstrumentation_logo, + com.android.internal.R.styleable.AndroidManifestInstrumentation_banner); mParseInstrumentationArgs.tag = "<instrumentation>"; } @@ -1961,6 +1967,8 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestApplication_icon, 0); ai.logo = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_logo, 0); + ai.banner = sa.getResourceId( + com.android.internal.R.styleable.AndroidManifestApplication_banner, 0); ai.theme = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestApplication_theme, 0); ai.descriptionRes = sa.getResourceId( @@ -2256,7 +2264,7 @@ public class PackageParser { private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo, String[] outError, String tag, TypedArray sa, - int nameRes, int labelRes, int iconRes, int logoRes) { + int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) { String name = sa.getNonConfigurationString(nameRes, 0); if (name == null) { outError[0] = tag + " does not specify android:name"; @@ -2280,6 +2288,11 @@ public class PackageParser { outInfo.logo = logoVal; } + int bannerVal = sa.getResourceId(bannerRes, 0); + if (bannerVal != 0) { + outInfo.banner = bannerVal; + } + TypedValue v = sa.peekValue(labelRes); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { outInfo.nonLocalizedLabel = v.coerceToString(); @@ -2303,6 +2316,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivity_label, com.android.internal.R.styleable.AndroidManifestActivity_icon, com.android.internal.R.styleable.AndroidManifestActivity_logo, + com.android.internal.R.styleable.AndroidManifestActivity_banner, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestActivity_process, com.android.internal.R.styleable.AndroidManifestActivity_description, @@ -2588,6 +2602,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestActivityAlias_label, com.android.internal.R.styleable.AndroidManifestActivityAlias_icon, com.android.internal.R.styleable.AndroidManifestActivityAlias_logo, + com.android.internal.R.styleable.AndroidManifestActivityAlias_banner, mSeparateProcesses, 0, com.android.internal.R.styleable.AndroidManifestActivityAlias_description, @@ -2622,6 +2637,7 @@ public class PackageParser { info.flags = target.info.flags; info.icon = target.info.icon; info.logo = target.info.logo; + info.banner = target.info.banner; info.labelRes = target.info.labelRes; info.nonLocalizedLabel = target.info.nonLocalizedLabel; info.launchMode = target.info.launchMode; @@ -2735,6 +2751,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestProvider_label, com.android.internal.R.styleable.AndroidManifestProvider_icon, com.android.internal.R.styleable.AndroidManifestProvider_logo, + com.android.internal.R.styleable.AndroidManifestProvider_banner, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestProvider_process, com.android.internal.R.styleable.AndroidManifestProvider_description, @@ -3041,6 +3058,7 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestService_label, com.android.internal.R.styleable.AndroidManifestService_icon, com.android.internal.R.styleable.AndroidManifestService_logo, + com.android.internal.R.styleable.AndroidManifestService_banner, mSeparateProcesses, com.android.internal.R.styleable.AndroidManifestService_process, com.android.internal.R.styleable.AndroidManifestService_description, @@ -3338,6 +3356,9 @@ public class PackageParser { outInfo.logo = sa.getResourceId( com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0); + outInfo.banner = sa.getResourceId( + com.android.internal.R.styleable.AndroidManifestIntentFilter_banner, 0); + sa.recycle(); int outerDepth = parser.getDepth(); @@ -3707,6 +3728,11 @@ public class PackageParser { outInfo.logo = logoVal; } + int bannerVal = args.sa.getResourceId(args.bannerRes, 0); + if (bannerVal != 0) { + outInfo.banner = bannerVal; + } + TypedValue v = args.sa.peekValue(args.labelRes); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { outInfo.nonLocalizedLabel = v.coerceToString(); @@ -4131,6 +4157,7 @@ public class PackageParser { public CharSequence nonLocalizedLabel; public int icon; public int logo; + public int banner; public int preferred; } diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index 875e8de..4a743a5 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -140,12 +140,33 @@ public abstract class RegisteredServicesCache<V> { mContext.registerReceiver(mExternalReceiver, sdFilter); } + private final void handlePackageEvent(Intent intent, int userId) { + // Don't regenerate the services map when the package is removed or its + // ASEC container unmounted as a step in replacement. The subsequent + // _ADDED / _AVAILABLE call will regenerate the map in the final state. + final String action = intent.getAction(); + // it's a new-component action if it isn't some sort of removal + final boolean isRemoval = Intent.ACTION_PACKAGE_REMOVED.equals(action) + || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action); + // if it's a removal, is it part of an update-in-place step? + final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + + if (isRemoval && replacing) { + // package is going away, but it's the middle of an upgrade: keep the current + // state and do nothing here. This clause is intentionally empty. + } else { + // either we're adding/changing, or it's a removal without replacement, so + // we need to recalculate the set of available services + generateServicesMap(userId); + } + } + private final BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); if (uid != -1) { - generateServicesMap(UserHandle.getUserId(uid)); + handlePackageEvent(intent, UserHandle.getUserId(uid)); } } }; @@ -154,7 +175,7 @@ public abstract class RegisteredServicesCache<V> { @Override public void onReceive(Context context, Intent intent) { // External apps can't coexist with multi-user, so scan owner - generateServicesMap(UserHandle.USER_OWNER); + handlePackageEvent(intent, UserHandle.USER_OWNER); } }; diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl index 542af6a..4c50dda 100644 --- a/core/java/android/hardware/ICameraService.aidl +++ b/core/java/android/hardware/ICameraService.aidl @@ -61,4 +61,12 @@ interface ICameraService int removeListener(ICameraServiceListener listener); int getCameraCharacteristics(int cameraId, out CameraMetadataNative info); + + /** + * The java stubs for this method are not intended to be used. Please use + * the native stub in frameworks/av/include/camera/ICameraService.h instead. + * The BinderHolder output is being used as a placeholder, and will not be + * well-formatted in the generated java method. + */ + int getCameraVendorTagDescriptor(out BinderHolder desc); } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index d27485b..4c04caa 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -148,7 +148,7 @@ public final class CameraCharacteristics extends CameraMetadata { * <p>All camera devices support ON, and all camera devices with * flash units support ON_AUTO_FLASH and * ON_ALWAYS_FLASH.</p> - * <p>Full-capability camera devices always support OFF mode, + * <p>FULL mode camera devices always support OFF mode, * which enables application control of camera exposure time, * sensitivity, and frame duration.</p> * @@ -244,7 +244,7 @@ public final class CameraCharacteristics extends CameraMetadata { * given camera device. This entry lists the valid modes for * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} for this camera device.</p> * <p>All camera devices will support ON mode.</p> - * <p>Full-capability camera devices will always support OFF mode, + * <p>FULL mode camera devices will always support OFF mode, * which enables application control of white balance, by using * {@link CaptureRequest#COLOR_CORRECTION_TRANSFORM android.colorCorrection.transform} and {@link CaptureRequest#COLOR_CORRECTION_GAINS android.colorCorrection.gains}({@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} must be set to TRANSFORM_MATRIX).</p> * @@ -280,6 +280,17 @@ public final class CameraCharacteristics extends CameraMetadata { new Key<Boolean>("android.flash.info.available", boolean.class); /** + * <p>The set of hot pixel correction modes that are supported by this + * camera device.</p> + * <p>This tag lists valid modes for {@link CaptureRequest#HOT_PIXEL_MODE android.hotPixel.mode}.</p> + * <p>FULL mode camera devices will always support FAST.</p> + * + * @see CaptureRequest#HOT_PIXEL_MODE + */ + public static final Key<byte[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES = + new Key<byte[]>("android.hotPixel.availableHotPixelModes", byte[].class); + + /** * <p>Supported resolutions for the JPEG thumbnail</p> * <p>Below condiditions will be satisfied for this size list:</p> * <ul> @@ -1088,6 +1099,18 @@ public final class CameraCharacteristics extends CameraMetadata { new Key<Integer>("android.statistics.info.maxFaceCount", int.class); /** + * <p>The set of hot pixel map output modes supported by this camera device.</p> + * <p>This tag lists valid output modes for {@link CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE android.statistics.hotPixelMapMode}.</p> + * <p>If no hotpixel map is available for this camera device, this will contain + * only OFF. If the hotpixel map is available, this should include both + * the ON and OFF options.</p> + * + * @see CaptureRequest#STATISTICS_HOT_PIXEL_MAP_MODE + */ + public static final Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES = + new Key<boolean[]>("android.statistics.info.availableHotPixelMapModes", boolean[].class); + + /** * <p>Maximum number of supported points in the * tonemap curve that can be used for {@link CaptureRequest#TONEMAP_CURVE_RED android.tonemap.curveRed}, or * {@link CaptureRequest#TONEMAP_CURVE_GREEN android.tonemap.curveGreen}, or {@link CaptureRequest#TONEMAP_CURVE_BLUE android.tonemap.curveBlue}.</p> diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 2ac50e4..78e7037 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -48,6 +48,8 @@ import java.util.ArrayList; */ public final class CameraManager { + private static final String TAG = "CameraManager"; + /** * This should match the ICameraService definition */ @@ -79,6 +81,19 @@ public final class CameraManager { mCameraService = CameraBinderDecorator.newInstance(cameraServiceRaw); try { + int err = CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor(); + if (err == CameraBinderDecorator.EOPNOTSUPP) { + Log.w(TAG, "HAL version doesn't vendor tags."); + } else { + CameraBinderDecorator.throwOnError(CameraMetadataNative. + nativeSetupGlobalVendorTagDescriptor()); + } + } catch(CameraRuntimeException e) { + throw new IllegalStateException("Failed to setup camera vendor tags", + e.asChecked()); + } + + try { mCameraService.addListener(new CameraServiceListener()); } catch(CameraRuntimeException e) { throw new IllegalStateException("Failed to register a camera service listener", diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index a62df0f..a3fbfbe 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -1199,7 +1199,10 @@ public abstract class CameraMetadata { /** * <p>The frame rate must not be reduced relative to sensor raw output * for this option.</p> - * <p>No hot pixel correction is applied.</p> + * <p>No hot pixel correction is applied. + * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p> + * + * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP * @see CaptureRequest#HOT_PIXEL_MODE */ public static final int HOT_PIXEL_MODE_OFF = 0; @@ -1207,7 +1210,10 @@ public abstract class CameraMetadata { /** * <p>The frame rate must not be reduced relative to sensor raw output * for this option.</p> - * <p>Hot pixel correction is applied.</p> + * <p>Hot pixel correction is applied. + * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p> + * + * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP * @see CaptureRequest#HOT_PIXEL_MODE */ public static final int HOT_PIXEL_MODE_FAST = 1; @@ -1215,7 +1221,10 @@ public abstract class CameraMetadata { /** * <p>The frame rate may be reduced relative to sensor raw output * for this option.</p> - * <p>A high-quality hot pixel correction is applied.</p> + * <p>A high-quality hot pixel correction is applied. + * The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p> + * + * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP * @see CaptureRequest#HOT_PIXEL_MODE */ public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index a8caba0..fbac529 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -876,9 +876,13 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { /** * <p>Set operational mode for hot pixel correction.</p> + * <p>Valid modes for this camera device are listed in + * {@link CameraCharacteristics#HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES android.hotPixel.availableHotPixelModes}.</p> * <p>Hotpixel correction interpolates out, or otherwise removes, pixels * that do not accurately encode the incoming light (i.e. pixels that * are stuck at an arbitrary value).</p> + * + * @see CameraCharacteristics#HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES * @see #HOT_PIXEL_MODE_OFF * @see #HOT_PIXEL_MODE_FAST * @see #HOT_PIXEL_MODE_HIGH_QUALITY @@ -1286,6 +1290,18 @@ public final class CaptureRequest extends CameraMetadata implements Parcelable { new Key<Integer>("android.statistics.faceDetectMode", int.class); /** + * <p>Operating mode for hotpixel map generation.</p> + * <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}. + * If set to OFF, no hotpixel map should be returned.</p> + * <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p> + * + * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP + * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES + */ + public static final Key<Boolean> STATISTICS_HOT_PIXEL_MAP_MODE = + new Key<Boolean>("android.statistics.hotPixelMapMode", boolean.class); + + /** * <p>Whether the camera device will output the lens * shading map in output result metadata.</p> * <p>When set to ON, diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 0f2c7f7..ab1525e 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -1166,24 +1166,14 @@ public final class CaptureResult extends CameraMetadata { new Key<Integer>("android.flash.state", int.class); /** - * <p>List of <code>(x, y)</code> coordinates of hot/defective pixels on the - * sensor, where <code>(x, y)</code> lies between <code>(0, 0)</code>, which is the top-left - * of the pixel array, and the width,height of the pixel array given in - * {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}. This may include hot pixels - * that lie outside of the active array bounds given by - * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> - * - * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE - * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE - */ - public static final Key<int[]> HOT_PIXEL_MAP = - new Key<int[]>("android.hotPixel.map", int[].class); - - /** * <p>Set operational mode for hot pixel correction.</p> + * <p>Valid modes for this camera device are listed in + * {@link CameraCharacteristics#HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES android.hotPixel.availableHotPixelModes}.</p> * <p>Hotpixel correction interpolates out, or otherwise removes, pixels * that do not accurately encode the incoming light (i.e. pixels that * are stuck at an arbitrary value).</p> + * + * @see CameraCharacteristics#HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES * @see #HOT_PIXEL_MODE_OFF * @see #HOT_PIXEL_MODE_FAST * @see #HOT_PIXEL_MODE_HIGH_QUALITY @@ -1971,6 +1961,33 @@ public final class CaptureResult extends CameraMetadata { new Key<Integer>("android.statistics.sceneFlicker", int.class); /** + * <p>Operating mode for hotpixel map generation.</p> + * <p>If set to ON, a hotpixel map is returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}. + * If set to OFF, no hotpixel map should be returned.</p> + * <p>This must be set to a valid mode from {@link CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES android.statistics.info.availableHotPixelMapModes}.</p> + * + * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP + * @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES + */ + public static final Key<Boolean> STATISTICS_HOT_PIXEL_MAP_MODE = + new Key<Boolean>("android.statistics.hotPixelMapMode", boolean.class); + + /** + * <p>List of <code>(x, y)</code> coordinates of hot/defective pixels on the sensor.</p> + * <p>A coordinate <code>(x, y)</code> must lie between <code>(0, 0)</code>, and + * <code>(width - 1, height - 1)</code> (inclusive), which are the top-left and + * bottom-right of the pixel array, respectively. The width and + * height dimensions are given in {@link CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE android.sensor.info.pixelArraySize}. + * This may include hot pixels that lie outside of the active array + * bounds given by {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p> + * + * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE + * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE + */ + public static final Key<int[]> STATISTICS_HOT_PIXEL_MAP = + new Key<int[]>("android.statistics.hotPixelMap", int[].class); + + /** * <p>Tonemapping / contrast / gamma curve for the blue * channel, to use when {@link CaptureRequest#TONEMAP_MODE android.tonemap.mode} is * CONTRAST_CURVE.</p> diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 2ddcb14..0d4a4cb 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -105,6 +105,18 @@ public class CameraMetadataNative extends CameraMetadata implements Parcelable { } /** + * Set the global client-side vendor tag descriptor to allow use of vendor + * tags in camera applications. + * + * @return int A native status_t value corresponding to one of the + * {@link CameraBinderDecorator} integer constants. + * @see CameraBinderDecorator#throwOnError + * + * @hide + */ + public static native int nativeSetupGlobalVendorTagDescriptor(); + + /** * Set a camera metadata field to a value. The field definitions can be * found in {@link CameraCharacteristics}, {@link CaptureResult}, and * {@link CaptureRequest}. diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java index e535e00..328ccbe 100644 --- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java +++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java @@ -64,47 +64,7 @@ public class CameraBinderDecorator { // int return type => status_t => convert to exception if (m.getReturnType() == Integer.TYPE) { int returnValue = (Integer) result; - - switch (returnValue) { - case NO_ERROR: - return; - case PERMISSION_DENIED: - throw new SecurityException("Lacking privileges to access camera service"); - case ALREADY_EXISTS: - // This should be handled at the call site. Typically this isn't bad, - // just means we tried to do an operation that already completed. - return; - case BAD_VALUE: - throw new IllegalArgumentException("Bad argument passed to camera service"); - case DEAD_OBJECT: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISCONNECTED)); - case EACCES: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISABLED)); - case EBUSY: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_IN_USE)); - case EUSERS: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - MAX_CAMERAS_IN_USE)); - case ENODEV: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DISCONNECTED)); - case EOPNOTSUPP: - UncheckedThrow.throwAnyException(new CameraRuntimeException( - CAMERA_DEPRECATED_HAL)); - } - - /** - * Trap the rest of the negative return values. If we have known - * error codes i.e. ALREADY_EXISTS that aren't really runtime - * errors, then add them to the top switch statement - */ - if (returnValue < 0) { - throw new UnsupportedOperationException(String.format("Unknown error %d", - returnValue)); - } + throwOnError(returnValue); } } @@ -131,6 +91,54 @@ public class CameraBinderDecorator { } /** + * Throw error codes returned by the camera service as exceptions. + * + * @param errorFlag error to throw as an exception. + */ + public static void throwOnError(int errorFlag) { + switch (errorFlag) { + case NO_ERROR: + return; + case PERMISSION_DENIED: + throw new SecurityException("Lacking privileges to access camera service"); + case ALREADY_EXISTS: + // This should be handled at the call site. Typically this isn't bad, + // just means we tried to do an operation that already completed. + return; + case BAD_VALUE: + throw new IllegalArgumentException("Bad argument passed to camera service"); + case DEAD_OBJECT: + UncheckedThrow.throwAnyException(new CameraRuntimeException( + CAMERA_DISCONNECTED)); + case EACCES: + UncheckedThrow.throwAnyException(new CameraRuntimeException( + CAMERA_DISABLED)); + case EBUSY: + UncheckedThrow.throwAnyException(new CameraRuntimeException( + CAMERA_IN_USE)); + case EUSERS: + UncheckedThrow.throwAnyException(new CameraRuntimeException( + MAX_CAMERAS_IN_USE)); + case ENODEV: + UncheckedThrow.throwAnyException(new CameraRuntimeException( + CAMERA_DISCONNECTED)); + case EOPNOTSUPP: + UncheckedThrow.throwAnyException(new CameraRuntimeException( + CAMERA_DEPRECATED_HAL)); + } + + /** + * Trap the rest of the negative return values. If we have known + * error codes i.e. ALREADY_EXISTS that aren't really runtime + * errors, then add them to the top switch statement + */ + if (errorFlag < 0) { + throw new UnsupportedOperationException(String.format("Unknown error %d", + errorFlag)); + } + } + + /** * <p> * Wraps the type T with a proxy that will check 'status_t' return codes * from the native side of the camera service, and throw Java exceptions diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java index 95faa77..6c61046 100644 --- a/core/java/android/net/EthernetDataTracker.java +++ b/core/java/android/net/EthernetDataTracker.java @@ -106,6 +106,24 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { mLinkCapabilities = new LinkCapabilities(); } + private void interfaceUpdated() { + // we don't get link status indications unless the iface is up - bring it up + try { + mNMService.setInterfaceUp(mIface); + String hwAddr = null; + InterfaceConfiguration config = mNMService.getInterfaceConfig(mIface); + if (config != null) { + hwAddr = config.getHardwareAddress(); + } + synchronized (this) { + mHwAddr = hwAddr; + mNetworkInfo.setExtraInfo(mHwAddr); + } + } catch (RemoteException e) { + Log.e(TAG, "Error upping interface " + mIface + ": " + e); + } + } + private void interfaceAdded(String iface) { if (!iface.matches(sIfaceMatch)) return; @@ -118,12 +136,7 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { mIface = iface; } - // we don't get link status indications unless the iface is up - bring it up - try { - mNMService.setInterfaceUp(iface); - } catch (Exception e) { - Log.e(TAG, "Error upping interface " + iface + ": " + e); - } + interfaceUpdated(); mNetworkInfo.setIsAvailable(true); Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo); @@ -159,7 +172,11 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { Log.d(TAG, "Removing " + iface); disconnect(); - mIface = ""; + synchronized (this) { + mIface = ""; + mHwAddr = null; + mNetworkInfo.setExtraInfo(null); + } } private void runDhcp() { @@ -220,15 +237,7 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { for (String iface : ifaces) { if (iface.matches(sIfaceMatch)) { mIface = iface; - mNMService.setInterfaceUp(iface); - InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); - mLinkUp = config.hasFlag("up"); - if (config != null && mHwAddr == null) { - mHwAddr = config.getHardwareAddress(); - if (mHwAddr != null) { - mNetworkInfo.setExtraInfo(mHwAddr); - } - } + interfaceUpdated(); // if a DHCP client had previously been started for this interface, then stop it NetworkUtils.stopDhcp(mIface); @@ -418,4 +427,9 @@ public class EthernetDataTracker extends BaseNetworkStateTracker { public void supplyMessenger(Messenger messenger) { // not supported on this network } + + @Override + public String getNetworkInterfaceName() { + return mIface; + } } diff --git a/core/java/android/print/PrinterCapabilitiesInfo.java b/core/java/android/print/PrinterCapabilitiesInfo.java index b615600..806a89d 100644 --- a/core/java/android/print/PrinterCapabilitiesInfo.java +++ b/core/java/android/print/PrinterCapabilitiesInfo.java @@ -475,6 +475,12 @@ public final class PrinterCapabilitiesInfo implements Parcelable { * @param colorModes The color mode bit mask. * @param defaultColorMode The default color mode. * @return This builder. + * <p> + * <strong>Note:</strong> On platform version 19 (Kitkat) specifying + * only PrintAttributes#COLOR_MODE_MONOCHROME leads to a print spooler + * crash. Hence, you should declare either both color modes or + * PrintAttributes#COLOR_MODE_COLOR. + * </p> * * @throws IllegalArgumentException If color modes contains an invalid * mode bit or if the default color mode is invalid. diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index be6f401..ed52803 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 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. @@ -16,916 +16,10 @@ package android.view; -import android.graphics.Matrix; -import android.graphics.Path; - -/** - * <p>A display list records a series of graphics related operations and can replay - * them later. Display lists are usually built by recording operations on a - * {@link HardwareCanvas}. Replaying the operations from a display list avoids - * executing application code on every frame, and is thus much more efficient.</p> - * - * <p>Display lists are used internally for all views by default, and are not - * typically used directly. One reason to consider using a display is a custom - * {@link View} implementation that needs to issue a large number of drawing commands. - * When the view invalidates, all the drawing commands must be reissued, even if - * large portions of the drawing command stream stay the same frame to frame, which - * can become a performance bottleneck. To solve this issue, a custom View might split - * its content into several display lists. A display list is updated only when its - * content, and only its content, needs to be updated.</p> - * - * <p>A text editor might for instance store each paragraph into its own display list. - * Thus when the user inserts or removes characters, only the display list of the - * affected paragraph needs to be recorded again.</p> - * - * <h3>Hardware acceleration</h3> - * <p>Display lists can only be replayed using a {@link HardwareCanvas}. They are not - * supported in software. Always make sure that the {@link android.graphics.Canvas} - * you are using to render a display list is hardware accelerated using - * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p> - * - * <h3>Creating a display list</h3> - * <pre class="prettyprint"> - * HardwareRenderer renderer = myView.getHardwareRenderer(); - * if (renderer != null) { - * DisplayList displayList = renderer.createDisplayList(); - * HardwareCanvas canvas = displayList.start(width, height); - * try { - * // Draw onto the canvas - * // For instance: canvas.drawBitmap(...); - * } finally { - * displayList.end(); - * } - * } - * </pre> - * - * <h3>Rendering a display list on a View</h3> - * <pre class="prettyprint"> - * protected void onDraw(Canvas canvas) { - * if (canvas.isHardwareAccelerated()) { - * HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas; - * hardwareCanvas.drawDisplayList(mDisplayList); - * } - * } - * </pre> - * - * <h3>Releasing resources</h3> - * <p>This step is not mandatory but recommended if you want to release resources - * held by a display list as soon as possible.</p> - * <pre class="prettyprint"> - * // Mark this display list invalid, it cannot be used for drawing anymore, - * // and release resources held by this display list - * displayList.clear(); - * </pre> - * - * <h3>Properties</h3> - * <p>In addition, a display list offers several properties, such as - * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all - * the drawing commands recorded within. For instance, these properties can be used - * to move around a large number of images without re-issuing all the individual - * <code>drawBitmap()</code> calls.</p> - * - * <pre class="prettyprint"> - * private void createDisplayList() { - * mDisplayList = DisplayList.create("MyDisplayList"); - * HardwareCanvas canvas = mDisplayList.start(width, height); - * try { - * for (Bitmap b : mBitmaps) { - * canvas.drawBitmap(b, 0.0f, 0.0f, null); - * canvas.translate(0.0f, b.getHeight()); - * } - * } finally { - * displayList.end(); - * } - * } - * - * protected void onDraw(Canvas canvas) { - * if (canvas.isHardwareAccelerated()) { - * HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas; - * hardwareCanvas.drawDisplayList(mDisplayList); - * } - * } - * - * private void moveContentBy(int x) { - * // This will move all the bitmaps recorded inside the display list - * // by x pixels to the right and redraw this view. All the commands - * // recorded in createDisplayList() won't be re-issued, only onDraw() - * // will be invoked and will execute very quickly - * mDisplayList.offsetLeftAndRight(x); - * invalidate(); - * } - * </pre> - * - * <h3>Threading</h3> - * <p>Display lists must be created on and manipulated from the UI thread only.</p> - * - * @hide +/** TODO: Remove once frameworks/webview is updated + * @hide */ public class DisplayList { - /** - * Flag used when calling - * {@link HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int)} - * When this flag is set, draw operations lying outside of the bounds of the - * display list will be culled early. It is recommeneded to always set this - * flag. - * - * @hide - */ - public static final int FLAG_CLIP_CHILDREN = 0x1; - - // NOTE: The STATUS_* values *must* match the enum in DrawGlInfo.h - - /** - * Indicates that the display list is done drawing. - * - * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) - * - * @hide - */ + /** @hide */ public static final int STATUS_DONE = 0x0; - - /** - * Indicates that the display list needs another drawing pass. - * - * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) - * - * @hide - */ - public static final int STATUS_DRAW = 0x1; - - /** - * Indicates that the display list needs to re-execute its GL functors. - * - * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) - * @see HardwareCanvas#callDrawGLFunction(long) - * - * @hide - */ - public static final int STATUS_INVOKE = 0x2; - - /** - * Indicates that the display list performed GL drawing operations. - * - * @see HardwareCanvas#drawDisplayList(DisplayList, android.graphics.Rect, int) - * - * @hide - */ - public static final int STATUS_DREW = 0x4; - - private boolean mValid; - private final long mNativeDisplayList; - private HardwareRenderer mRenderer; - - private DisplayList(String name) { - mNativeDisplayList = nCreate(); - nSetDisplayListName(mNativeDisplayList, name); - } - - /** - * Creates a new display list that can be used to record batches of - * drawing operations. - * - * @param name The name of the display list, used for debugging purpose. May be null. - * - * @return A new display list. - * - * @hide - */ - public static DisplayList create(String name) { - return new DisplayList(name); - } - - /** - * Starts recording the display list. All operations performed on the - * returned canvas are recorded and stored in this display list. - * - * Calling this method will mark the display list invalid until - * {@link #end()} is called. Only valid display lists can be replayed. - * - * @param width The width of the display list's viewport - * @param height The height of the display list's viewport - * - * @return A canvas to record drawing operations. - * - * @see #end() - * @see #isValid() - */ - public HardwareCanvas start(int width, int height) { - HardwareCanvas canvas = GLES20RecordingCanvas.obtain(); - canvas.setViewport(width, height); - // The dirty rect should always be null for a display list - canvas.onPreDraw(null); - return canvas; - } - - /** - * Ends the recording for this display list. A display list cannot be - * replayed if recording is not finished. Calling this method marks - * the display list valid and {@link #isValid()} will return true. - * - * @see #start(int, int) - * @see #isValid() - */ - public void end(HardwareRenderer renderer, HardwareCanvas endCanvas) { - if (!(endCanvas instanceof GLES20RecordingCanvas)) { - throw new IllegalArgumentException("Passed an invalid canvas to end!"); - } - - GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas; - canvas.onPostDraw(); - long displayListData = canvas.finishRecording(); - if (renderer != mRenderer) { - // If we are changing renderers first destroy with the old - // renderer, then set with the new one - destroyDisplayListData(); - } - mRenderer = renderer; - setDisplayListData(displayListData); - canvas.recycle(); - mValid = true; - } - - /** - * Reset native resources. This is called when cleaning up the state of display lists - * during destruction of hardware resources, to ensure that we do not hold onto - * obsolete resources after related resources are gone. - * - * @hide - */ - public void destroyDisplayListData() { - if (!mValid) return; - - setDisplayListData(0); - mRenderer = null; - mValid = false; - } - - private void setDisplayListData(long newData) { - if (mRenderer != null) { - mRenderer.setDisplayListData(mNativeDisplayList, newData); - } else { - throw new IllegalStateException("Trying to set data without a renderer! data=" + newData); - } - } - - /** - * Returns whether the display list is currently usable. If this returns false, - * the display list should be re-recorded prior to replaying it. - * - * @return boolean true if the display list is able to be replayed, false otherwise. - */ - public boolean isValid() { return mValid; } - - long getNativeDisplayList() { - if (!mValid) { - throw new IllegalStateException("The display list is not valid."); - } - return mNativeDisplayList; - } - - /////////////////////////////////////////////////////////////////////////// - // DisplayList Property Setters - /////////////////////////////////////////////////////////////////////////// - - /** - * Set the caching property on the display list, which indicates whether the display list - * holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is - * handled in the drawLayer operation directly (and more efficiently). - * - * @param caching true if the display list represents a hardware layer, false otherwise. - * - * @hide - */ - public void setCaching(boolean caching) { - nSetCaching(mNativeDisplayList, caching); - } - - /** - * Set whether the display list should clip itself to its bounds. This property is controlled by - * the view's parent. - * - * @param clipToBounds true if the display list should clip to its bounds - */ - public void setClipToBounds(boolean clipToBounds) { - nSetClipToBounds(mNativeDisplayList, clipToBounds); - } - - /** - * Set whether the display list should collect and Z order all 3d composited descendents, and - * draw them in order with the default Z=0 content. - * - * @param isolatedZVolume true if the display list should collect and Z order descendents. - */ - public void setIsolatedZVolume(boolean isolatedZVolume) { - nSetIsolatedZVolume(mNativeDisplayList, isolatedZVolume); - } - - /** - * Sets whether the display list should be drawn immediately after the - * closest ancestor display list where isolateZVolume is true. If the - * display list itself satisfies this constraint, changing this attribute - * has no effect on drawing order. - * - * @param shouldProject true if the display list should be projected onto a - * containing volume. - */ - public void setProjectBackwards(boolean shouldProject) { - nSetProjectBackwards(mNativeDisplayList, shouldProject); - } - - /** - * Sets whether the display list is a projection receiver - that its parent - * DisplayList should draw any descendent DisplayLists with - * ProjectBackwards=true directly on top of it. Default value is false. - */ - public void setProjectionReceiver(boolean shouldRecieve) { - nSetProjectionReceiver(mNativeDisplayList, shouldRecieve); - } - - /** - * Sets the outline, defining the shape that casts a shadow, and the path to - * be clipped if setClipToOutline is set. - * - * Deep copies the native path to simplify reference ownership. - * - * @param outline Convex, CW Path to store in the DisplayList. May be null. - */ - public void setOutline(Path outline) { - long nativePath = (outline == null) ? 0 : outline.mNativePath; - nSetOutline(mNativeDisplayList, nativePath); - } - - /** - * Enables or disables clipping to the outline. - * - * @param clipToOutline true if clipping to the outline. - */ - public void setClipToOutline(boolean clipToOutline) { - nSetClipToOutline(mNativeDisplayList, clipToOutline); - } - - /** - * Set whether the DisplayList should cast a shadow. - * - * The shape of the shadow casting area is defined by the outline of the display list, if set - * and non-empty, otherwise it will be the bounds rect. - */ - public void setCastsShadow(boolean castsShadow) { - nSetCastsShadow(mNativeDisplayList, castsShadow); - } - - /** - * Sets whether the DisplayList should be drawn with perspective applied from the global camera. - * - * If set to true, camera distance will be ignored. Defaults to false. - */ - public void setUsesGlobalCamera(boolean usesGlobalCamera) { - nSetUsesGlobalCamera(mNativeDisplayList, usesGlobalCamera); - } - - /** - * Set the static matrix on the display list. The specified matrix is combined with other - * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.) - * - * @param matrix A transform matrix to apply to this display list - * - * @see #getMatrix(android.graphics.Matrix) - * @see #getMatrix() - */ - public void setStaticMatrix(Matrix matrix) { - nSetStaticMatrix(mNativeDisplayList, matrix.native_instance); - } - - /** - * Set the Animation matrix on the display list. This matrix exists if an Animation is - * currently playing on a View, and is set on the display list during at draw() time. When - * the Animation finishes, the matrix should be cleared by sending <code>null</code> - * for the matrix parameter. - * - * @param matrix The matrix, null indicates that the matrix should be cleared. - * - * @hide - */ - public void setAnimationMatrix(Matrix matrix) { - nSetAnimationMatrix(mNativeDisplayList, - (matrix != null) ? matrix.native_instance : 0); - } - - /** - * Sets the translucency level for the display list. - * - * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f - * - * @see View#setAlpha(float) - * @see #getAlpha() - */ - public void setAlpha(float alpha) { - nSetAlpha(mNativeDisplayList, alpha); - } - - /** - * Returns the translucency level of this display list. - * - * @return A value between 0.0f and 1.0f - * - * @see #setAlpha(float) - */ - public float getAlpha() { - return nGetAlpha(mNativeDisplayList); - } - - /** - * Sets whether the display list renders content which overlaps. Non-overlapping rendering - * can use a fast path for alpha that avoids rendering to an offscreen buffer. By default - * display lists consider they do not have overlapping content. - * - * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping, - * true otherwise. - * - * @see android.view.View#hasOverlappingRendering() - * @see #hasOverlappingRendering() - */ - public void setHasOverlappingRendering(boolean hasOverlappingRendering) { - nSetHasOverlappingRendering(mNativeDisplayList, hasOverlappingRendering); - } - - /** - * Indicates whether the content of this display list overlaps. - * - * @return True if this display list renders content which overlaps, false otherwise. - * - * @see #setHasOverlappingRendering(boolean) - */ - public boolean hasOverlappingRendering() { - //noinspection SimplifiableIfStatement - return nHasOverlappingRendering(mNativeDisplayList); - } - - /** - * Sets the translation value for the display list on the X axis. - * - * @param translationX The X axis translation value of the display list, in pixels - * - * @see View#setTranslationX(float) - * @see #getTranslationX() - */ - public void setTranslationX(float translationX) { - nSetTranslationX(mNativeDisplayList, translationX); - } - - /** - * Returns the translation value for this display list on the X axis, in pixels. - * - * @see #setTranslationX(float) - */ - public float getTranslationX() { - return nGetTranslationX(mNativeDisplayList); - } - - /** - * Sets the translation value for the display list on the Y axis. - * - * @param translationY The Y axis translation value of the display list, in pixels - * - * @see View#setTranslationY(float) - * @see #getTranslationY() - */ - public void setTranslationY(float translationY) { - nSetTranslationY(mNativeDisplayList, translationY); - } - - /** - * Returns the translation value for this display list on the Y axis, in pixels. - * - * @see #setTranslationY(float) - */ - public float getTranslationY() { - return nGetTranslationY(mNativeDisplayList); - } - - /** - * Sets the translation value for the display list on the Z axis. - * - * @see View#setTranslationZ(float) - * @see #getTranslationZ() - */ - public void setTranslationZ(float translationZ) { - nSetTranslationZ(mNativeDisplayList, translationZ); - } - - /** - * Returns the translation value for this display list on the Z axis. - * - * @see #setTranslationZ(float) - */ - public float getTranslationZ() { - return nGetTranslationZ(mNativeDisplayList); - } - - /** - * Sets the rotation value for the display list around the Z axis. - * - * @param rotation The rotation value of the display list, in degrees - * - * @see View#setRotation(float) - * @see #getRotation() - */ - public void setRotation(float rotation) { - nSetRotation(mNativeDisplayList, rotation); - } - - /** - * Returns the rotation value for this display list around the Z axis, in degrees. - * - * @see #setRotation(float) - */ - public float getRotation() { - return nGetRotation(mNativeDisplayList); - } - - /** - * Sets the rotation value for the display list around the X axis. - * - * @param rotationX The rotation value of the display list, in degrees - * - * @see View#setRotationX(float) - * @see #getRotationX() - */ - public void setRotationX(float rotationX) { - nSetRotationX(mNativeDisplayList, rotationX); - } - - /** - * Returns the rotation value for this display list around the X axis, in degrees. - * - * @see #setRotationX(float) - */ - public float getRotationX() { - return nGetRotationX(mNativeDisplayList); - } - - /** - * Sets the rotation value for the display list around the Y axis. - * - * @param rotationY The rotation value of the display list, in degrees - * - * @see View#setRotationY(float) - * @see #getRotationY() - */ - public void setRotationY(float rotationY) { - nSetRotationY(mNativeDisplayList, rotationY); - } - - /** - * Returns the rotation value for this display list around the Y axis, in degrees. - * - * @see #setRotationY(float) - */ - public float getRotationY() { - return nGetRotationY(mNativeDisplayList); - } - - /** - * Sets the scale value for the display list on the X axis. - * - * @param scaleX The scale value of the display list - * - * @see View#setScaleX(float) - * @see #getScaleX() - */ - public void setScaleX(float scaleX) { - nSetScaleX(mNativeDisplayList, scaleX); - } - - /** - * Returns the scale value for this display list on the X axis. - * - * @see #setScaleX(float) - */ - public float getScaleX() { - return nGetScaleX(mNativeDisplayList); - } - - /** - * Sets the scale value for the display list on the Y axis. - * - * @param scaleY The scale value of the display list - * - * @see View#setScaleY(float) - * @see #getScaleY() - */ - public void setScaleY(float scaleY) { - nSetScaleY(mNativeDisplayList, scaleY); - } - - /** - * Returns the scale value for this display list on the Y axis. - * - * @see #setScaleY(float) - */ - public float getScaleY() { - return nGetScaleY(mNativeDisplayList); - } - - /** - * Sets all of the transform-related values of the display list - * - * @param alpha The alpha value of the display list - * @param translationX The translationX value of the display list - * @param translationY The translationY value of the display list - * @param rotation The rotation value of the display list - * @param rotationX The rotationX value of the display list - * @param rotationY The rotationY value of the display list - * @param scaleX The scaleX value of the display list - * @param scaleY The scaleY value of the display list - * - * @hide - */ - public void setTransformationInfo(float alpha, - float translationX, float translationY, float translationZ, - float rotation, float rotationX, float rotationY, float scaleX, float scaleY) { - nSetTransformationInfo(mNativeDisplayList, alpha, - translationX, translationY, translationZ, - rotation, rotationX, rotationY, scaleX, scaleY); - } - - /** - * Sets the pivot value for the display list on the X axis - * - * @param pivotX The pivot value of the display list on the X axis, in pixels - * - * @see View#setPivotX(float) - * @see #getPivotX() - */ - public void setPivotX(float pivotX) { - nSetPivotX(mNativeDisplayList, pivotX); - } - - /** - * Returns the pivot value for this display list on the X axis, in pixels. - * - * @see #setPivotX(float) - */ - public float getPivotX() { - return nGetPivotX(mNativeDisplayList); - } - - /** - * Sets the pivot value for the display list on the Y axis - * - * @param pivotY The pivot value of the display list on the Y axis, in pixels - * - * @see View#setPivotY(float) - * @see #getPivotY() - */ - public void setPivotY(float pivotY) { - nSetPivotY(mNativeDisplayList, pivotY); - } - - /** - * Returns the pivot value for this display list on the Y axis, in pixels. - * - * @see #setPivotY(float) - */ - public float getPivotY() { - return nGetPivotY(mNativeDisplayList); - } - - /** - * Sets the camera distance for the display list. Refer to - * {@link View#setCameraDistance(float)} for more information on how to - * use this property. - * - * @param distance The distance in Z of the camera of the display list - * - * @see View#setCameraDistance(float) - * @see #getCameraDistance() - */ - public void setCameraDistance(float distance) { - nSetCameraDistance(mNativeDisplayList, distance); - } - - /** - * Returns the distance in Z of the camera of the display list. - * - * @see #setCameraDistance(float) - */ - public float getCameraDistance() { - return nGetCameraDistance(mNativeDisplayList); - } - - /** - * Sets the left position for the display list. - * - * @param left The left position, in pixels, of the display list - * - * @see View#setLeft(int) - * @see #getLeft() - */ - public void setLeft(int left) { - nSetLeft(mNativeDisplayList, left); - } - - /** - * Returns the left position for the display list in pixels. - * - * @see #setLeft(int) - */ - public float getLeft() { - return nGetLeft(mNativeDisplayList); - } - - /** - * Sets the top position for the display list. - * - * @param top The top position, in pixels, of the display list - * - * @see View#setTop(int) - * @see #getTop() - */ - public void setTop(int top) { - nSetTop(mNativeDisplayList, top); - } - - /** - * Returns the top position for the display list in pixels. - * - * @see #setTop(int) - */ - public float getTop() { - return nGetTop(mNativeDisplayList); - } - - /** - * Sets the right position for the display list. - * - * @param right The right position, in pixels, of the display list - * - * @see View#setRight(int) - * @see #getRight() - */ - public void setRight(int right) { - nSetRight(mNativeDisplayList, right); - } - - /** - * Returns the right position for the display list in pixels. - * - * @see #setRight(int) - */ - public float getRight() { - return nGetRight(mNativeDisplayList); - } - - /** - * Sets the bottom position for the display list. - * - * @param bottom The bottom position, in pixels, of the display list - * - * @see View#setBottom(int) - * @see #getBottom() - */ - public void setBottom(int bottom) { - nSetBottom(mNativeDisplayList, bottom); - } - - /** - * Returns the bottom position for the display list in pixels. - * - * @see #setBottom(int) - */ - public float getBottom() { - return nGetBottom(mNativeDisplayList); - } - - /** - * Sets the left and top positions for the display list - * - * @param left The left position of the display list, in pixels - * @param top The top position of the display list, in pixels - * @param right The right position of the display list, in pixels - * @param bottom The bottom position of the display list, in pixels - * - * @see View#setLeft(int) - * @see View#setTop(int) - * @see View#setRight(int) - * @see View#setBottom(int) - */ - public void setLeftTopRightBottom(int left, int top, int right, int bottom) { - nSetLeftTopRightBottom(mNativeDisplayList, left, top, right, bottom); - } - - /** - * Offsets the left and right positions for the display list - * - * @param offset The amount that the left and right positions of the display - * list are offset, in pixels - * - * @see View#offsetLeftAndRight(int) - */ - public void offsetLeftAndRight(float offset) { - nOffsetLeftAndRight(mNativeDisplayList, offset); - } - - /** - * Offsets the top and bottom values for the display list - * - * @param offset The amount that the top and bottom positions of the display - * list are offset, in pixels - * - * @see View#offsetTopAndBottom(int) - */ - public void offsetTopAndBottom(float offset) { - nOffsetTopAndBottom(mNativeDisplayList, offset); - } - - /** - * Outputs the display list to the log. This method exists for use by - * tools to output display lists for selected nodes to the log. - * - * @hide - */ - public void output() { - nOutput(mNativeDisplayList); - } - - /////////////////////////////////////////////////////////////////////////// - // Native methods - /////////////////////////////////////////////////////////////////////////// - - private static native long nCreate(); - private static native void nDestroyDisplayList(long displayList); - private static native void nSetDisplayListName(long displayList, String name); - - // Properties - - private static native void nOffsetTopAndBottom(long displayList, float offset); - private static native void nOffsetLeftAndRight(long displayList, float offset); - private static native void nSetLeftTopRightBottom(long displayList, int left, int top, - int right, int bottom); - private static native void nSetBottom(long displayList, int bottom); - private static native void nSetRight(long displayList, int right); - private static native void nSetTop(long displayList, int top); - private static native void nSetLeft(long displayList, int left); - private static native void nSetCameraDistance(long displayList, float distance); - private static native void nSetPivotY(long displayList, float pivotY); - private static native void nSetPivotX(long displayList, float pivotX); - private static native void nSetCaching(long displayList, boolean caching); - private static native void nSetClipToBounds(long displayList, boolean clipToBounds); - private static native void nSetProjectBackwards(long displayList, boolean shouldProject); - private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve); - private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume); - 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 nSetUsesGlobalCamera(long displayList, boolean usesGlobalCamera); - private static native void nSetAlpha(long displayList, float alpha); - private static native void nSetHasOverlappingRendering(long displayList, - boolean hasOverlappingRendering); - private static native void nSetTranslationX(long displayList, float translationX); - private static native void nSetTranslationY(long displayList, float translationY); - private static native void nSetTranslationZ(long displayList, float translationZ); - private static native void nSetRotation(long displayList, float rotation); - private static native void nSetRotationX(long displayList, float rotationX); - private static native void nSetRotationY(long displayList, float rotationY); - private static native void nSetScaleX(long displayList, float scaleX); - private static native void nSetScaleY(long displayList, float scaleY); - private static native void nSetTransformationInfo(long displayList, float alpha, - float translationX, float translationY, float translationZ, - float rotation, float rotationX, float rotationY, float scaleX, float scaleY); - private static native void nSetStaticMatrix(long displayList, long nativeMatrix); - private static native void nSetAnimationMatrix(long displayList, long animationMatrix); - - private static native boolean nHasOverlappingRendering(long displayList); - private static native float nGetAlpha(long displayList); - private static native float nGetLeft(long displayList); - private static native float nGetTop(long displayList); - private static native float nGetRight(long displayList); - private static native float nGetBottom(long displayList); - private static native float nGetCameraDistance(long displayList); - private static native float nGetScaleX(long displayList); - private static native float nGetScaleY(long displayList); - private static native float nGetTranslationX(long displayList); - private static native float nGetTranslationY(long displayList); - private static native float nGetTranslationZ(long displayList); - private static native float nGetRotation(long displayList); - private static native float nGetRotationX(long displayList); - private static native float nGetRotationY(long displayList); - private static native float nGetPivotX(long displayList); - private static native float nGetPivotY(long displayList); - private static native void nOutput(long displayList); - - /////////////////////////////////////////////////////////////////////////// - // Finalization - /////////////////////////////////////////////////////////////////////////// - - @Override - protected void finalize() throws Throwable { - try { - destroyDisplayListData(); - nDestroyDisplayList(mNativeDisplayList); - } finally { - super.finalize(); - } - } } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 6c6fc9b..c274fc4 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -359,7 +359,7 @@ class GLES20Canvas extends HardwareCanvas { protected static native long nFinishRecording(long renderer); @Override - public int drawDisplayList(DisplayList displayList, Rect dirty, int flags) { + public int drawDisplayList(RenderNode displayList, Rect dirty, int flags) { return nDrawDisplayList(mRenderer, displayList.getNativeDisplayList(), dirty, flags); } diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java index 81f778d..4d42c5d 100644 --- a/core/java/android/view/GLRenderer.java +++ b/core/java/android/view/GLRenderer.java @@ -1125,7 +1125,7 @@ public class GLRenderer extends HardwareRenderer { dirty = beginFrame(canvas, dirty, surfaceState); - DisplayList displayList = buildDisplayList(view, canvas); + RenderNode displayList = buildDisplayList(view, canvas); flushLayerChanges(); @@ -1137,7 +1137,7 @@ public class GLRenderer extends HardwareRenderer { } int saveCount = 0; - int status = DisplayList.STATUS_DONE; + int status = RenderNode.STATUS_DONE; long start = getSystemTime(); try { @@ -1201,7 +1201,7 @@ public class GLRenderer extends HardwareRenderer { } private static native void nSetDisplayListData(long displayList, long newData); - private DisplayList buildDisplayList(View view, HardwareCanvas canvas) { + private RenderNode buildDisplayList(View view, HardwareCanvas canvas) { if (mDrawDelta <= 0) { return view.mDisplayList; } @@ -1214,7 +1214,7 @@ public class GLRenderer extends HardwareRenderer { canvas.clearLayerUpdates(); Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); - DisplayList displayList = view.getDisplayList(); + RenderNode displayList = view.getDisplayList(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); endBuildDisplayListProfiling(buildDisplayListStartTime); @@ -1279,7 +1279,7 @@ public class GLRenderer extends HardwareRenderer { } private int drawDisplayList(View.AttachInfo attachInfo, HardwareCanvas canvas, - DisplayList displayList, int status) { + RenderNode displayList, int status) { long drawDisplayListStartTime = 0; if (mProfileEnabled) { @@ -1289,7 +1289,7 @@ public class GLRenderer extends HardwareRenderer { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "drawDisplayList"); try { status |= canvas.drawDisplayList(displayList, mRedrawClip, - DisplayList.FLAG_CLIP_CHILDREN); + RenderNode.FLAG_CLIP_CHILDREN); } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } @@ -1305,7 +1305,7 @@ public class GLRenderer extends HardwareRenderer { } private void swapBuffers(int status) { - if ((status & DisplayList.STATUS_DREW) == DisplayList.STATUS_DREW) { + if ((status & RenderNode.STATUS_DREW) == RenderNode.STATUS_DREW) { long eglSwapBuffersStartTime = 0; if (mProfileEnabled) { eglSwapBuffersStartTime = System.nanoTime(); @@ -1339,7 +1339,7 @@ public class GLRenderer extends HardwareRenderer { private void handleFunctorStatus(View.AttachInfo attachInfo, int status) { // If the draw flag is set, functors will be invoked while executing // the tree of display lists - if ((status & DisplayList.STATUS_DRAW) != 0) { + if ((status & RenderNode.STATUS_DRAW) != 0) { if (mRedrawClip.isEmpty()) { attachInfo.mViewRootImpl.invalidate(); } else { @@ -1348,7 +1348,7 @@ public class GLRenderer extends HardwareRenderer { } } - if ((status & DisplayList.STATUS_INVOKE) != 0 || + if ((status & RenderNode.STATUS_INVOKE) != 0 || attachInfo.mHandler.hasCallbacks(mFunctorsRunnable)) { attachInfo.mHandler.removeCallbacks(mFunctorsRunnable); mFunctorsRunnable.attachInfo = attachInfo; diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index a3c7b63..f695b20 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -42,7 +42,7 @@ public abstract class HardwareCanvas extends Canvas { * Invoked before any drawing operation is performed in this canvas. * * @param dirty The dirty rectangle to update, can be null. - * @return {@link DisplayList#STATUS_DREW} if anything was drawn (such as a call to clear + * @return {@link RenderNode#STATUS_DREW} if anything was drawn (such as a call to clear * the canvas). * * @hide @@ -58,12 +58,12 @@ public abstract class HardwareCanvas extends Canvas { /** * Draws the specified display list onto this canvas. The display list can only - * be drawn if {@link android.view.DisplayList#isValid()} returns true. + * be drawn if {@link android.view.RenderNode#isValid()} returns true. * * @param displayList The display list to replay. */ - public void drawDisplayList(DisplayList displayList) { - drawDisplayList(displayList, null, DisplayList.FLAG_CLIP_CHILDREN); + public void drawDisplayList(RenderNode displayList) { + drawDisplayList(displayList, null, RenderNode.FLAG_CLIP_CHILDREN); } /** @@ -71,17 +71,17 @@ public abstract class HardwareCanvas extends Canvas { * * @param displayList The display list to replay. * @param dirty The dirty region to redraw in the next pass, matters only - * if this method returns {@link DisplayList#STATUS_DRAW}, can be null. - * @param flags Optional flags about drawing, see {@link DisplayList} for + * if this method returns {@link RenderNode#STATUS_DRAW}, can be null. + * @param flags Optional flags about drawing, see {@link RenderNode} for * the possible flags. * - * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW}, or - * {@link DisplayList#STATUS_INVOKE}, or'd with {@link DisplayList#STATUS_DREW} + * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW}, or + * {@link RenderNode#STATUS_INVOKE}, or'd with {@link RenderNode#STATUS_DREW} * if anything was drawn. * * @hide */ - public abstract int drawDisplayList(DisplayList displayList, Rect dirty, int flags); + public abstract int drawDisplayList(RenderNode displayList, Rect dirty, int flags); /** * Draws the specified layer onto this canvas. @@ -102,28 +102,28 @@ public abstract class HardwareCanvas extends Canvas { * * @param drawGLFunction A native function pointer * - * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or - * {@link DisplayList#STATUS_INVOKE} + * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW} or + * {@link RenderNode#STATUS_INVOKE} * * @hide */ public int callDrawGLFunction(long drawGLFunction) { // Noop - this is done in the display list recorder subclass - return DisplayList.STATUS_DONE; + return RenderNode.STATUS_DONE; } /** * Invoke all the functors who requested to be invoked during the previous frame. * - * @param dirty The region to redraw when the functors return {@link DisplayList#STATUS_DRAW} + * @param dirty The region to redraw when the functors return {@link RenderNode#STATUS_DRAW} * - * @return One of {@link DisplayList#STATUS_DONE}, {@link DisplayList#STATUS_DRAW} or - * {@link DisplayList#STATUS_INVOKE} + * @return One of {@link RenderNode#STATUS_DONE}, {@link RenderNode#STATUS_DRAW} or + * {@link RenderNode#STATUS_INVOKE} * * @hide */ public int invokeFunctors(Rect dirty) { - return DisplayList.STATUS_DONE; + return RenderNode.STATUS_DONE; } /** diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java index 46e2690..4d78733 100644 --- a/core/java/android/view/HardwareLayer.java +++ b/core/java/android/view/HardwareLayer.java @@ -37,7 +37,7 @@ final class HardwareLayer { private HardwareRenderer mRenderer; private Finalizer mFinalizer; - private DisplayList mDisplayList; + private RenderNode mDisplayList; private final int mLayerType; private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) { @@ -122,11 +122,11 @@ final class HardwareLayer { } } - public DisplayList startRecording() { + public RenderNode startRecording() { assertType(LAYER_TYPE_DISPLAY_LIST); if (mDisplayList == null) { - mDisplayList = DisplayList.create("HardwareLayer"); + mDisplayList = RenderNode.create("HardwareLayer"); } return mDisplayList; } diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java new file mode 100644 index 0000000..430bf5e --- /dev/null +++ b/core/java/android/view/RenderNode.java @@ -0,0 +1,931 @@ +/* + * 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.view; + +import android.graphics.Matrix; +import android.graphics.Path; + +/** + * <p>A display list records a series of graphics related operations and can replay + * them later. Display lists are usually built by recording operations on a + * {@link HardwareCanvas}. Replaying the operations from a display list avoids + * executing application code on every frame, and is thus much more efficient.</p> + * + * <p>Display lists are used internally for all views by default, and are not + * typically used directly. One reason to consider using a display is a custom + * {@link View} implementation that needs to issue a large number of drawing commands. + * When the view invalidates, all the drawing commands must be reissued, even if + * large portions of the drawing command stream stay the same frame to frame, which + * can become a performance bottleneck. To solve this issue, a custom View might split + * its content into several display lists. A display list is updated only when its + * content, and only its content, needs to be updated.</p> + * + * <p>A text editor might for instance store each paragraph into its own display list. + * Thus when the user inserts or removes characters, only the display list of the + * affected paragraph needs to be recorded again.</p> + * + * <h3>Hardware acceleration</h3> + * <p>Display lists can only be replayed using a {@link HardwareCanvas}. They are not + * supported in software. Always make sure that the {@link android.graphics.Canvas} + * you are using to render a display list is hardware accelerated using + * {@link android.graphics.Canvas#isHardwareAccelerated()}.</p> + * + * <h3>Creating a display list</h3> + * <pre class="prettyprint"> + * HardwareRenderer renderer = myView.getHardwareRenderer(); + * if (renderer != null) { + * DisplayList displayList = renderer.createDisplayList(); + * HardwareCanvas canvas = displayList.start(width, height); + * try { + * // Draw onto the canvas + * // For instance: canvas.drawBitmap(...); + * } finally { + * displayList.end(); + * } + * } + * </pre> + * + * <h3>Rendering a display list on a View</h3> + * <pre class="prettyprint"> + * protected void onDraw(Canvas canvas) { + * if (canvas.isHardwareAccelerated()) { + * HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas; + * hardwareCanvas.drawDisplayList(mDisplayList); + * } + * } + * </pre> + * + * <h3>Releasing resources</h3> + * <p>This step is not mandatory but recommended if you want to release resources + * held by a display list as soon as possible.</p> + * <pre class="prettyprint"> + * // Mark this display list invalid, it cannot be used for drawing anymore, + * // and release resources held by this display list + * displayList.clear(); + * </pre> + * + * <h3>Properties</h3> + * <p>In addition, a display list offers several properties, such as + * {@link #setScaleX(float)} or {@link #setLeft(int)}, that can be used to affect all + * the drawing commands recorded within. For instance, these properties can be used + * to move around a large number of images without re-issuing all the individual + * <code>drawBitmap()</code> calls.</p> + * + * <pre class="prettyprint"> + * private void createDisplayList() { + * mDisplayList = DisplayList.create("MyDisplayList"); + * HardwareCanvas canvas = mDisplayList.start(width, height); + * try { + * for (Bitmap b : mBitmaps) { + * canvas.drawBitmap(b, 0.0f, 0.0f, null); + * canvas.translate(0.0f, b.getHeight()); + * } + * } finally { + * displayList.end(); + * } + * } + * + * protected void onDraw(Canvas canvas) { + * if (canvas.isHardwareAccelerated()) { + * HardwareCanvas hardwareCanvas = (HardwareCanvas) canvas; + * hardwareCanvas.drawDisplayList(mDisplayList); + * } + * } + * + * private void moveContentBy(int x) { + * // This will move all the bitmaps recorded inside the display list + * // by x pixels to the right and redraw this view. All the commands + * // recorded in createDisplayList() won't be re-issued, only onDraw() + * // will be invoked and will execute very quickly + * mDisplayList.offsetLeftAndRight(x); + * invalidate(); + * } + * </pre> + * + * <h3>Threading</h3> + * <p>Display lists must be created on and manipulated from the UI thread only.</p> + * + * @hide + */ +public class RenderNode { + /** + * Flag used when calling + * {@link HardwareCanvas#drawDisplayList(RenderNode, android.graphics.Rect, int)} + * When this flag is set, draw operations lying outside of the bounds of the + * display list will be culled early. It is recommeneded to always set this + * flag. + * + * @hide + */ + public static final int FLAG_CLIP_CHILDREN = 0x1; + + // NOTE: The STATUS_* values *must* match the enum in DrawGlInfo.h + + /** + * Indicates that the display list is done drawing. + * + * @see HardwareCanvas#drawDisplayList(RenderNode, android.graphics.Rect, int) + * + * @hide + */ + public static final int STATUS_DONE = 0x0; + + /** + * Indicates that the display list needs another drawing pass. + * + * @see HardwareCanvas#drawDisplayList(RenderNode, android.graphics.Rect, int) + * + * @hide + */ + public static final int STATUS_DRAW = 0x1; + + /** + * Indicates that the display list needs to re-execute its GL functors. + * + * @see HardwareCanvas#drawDisplayList(RenderNode, android.graphics.Rect, int) + * @see HardwareCanvas#callDrawGLFunction(long) + * + * @hide + */ + public static final int STATUS_INVOKE = 0x2; + + /** + * Indicates that the display list performed GL drawing operations. + * + * @see HardwareCanvas#drawDisplayList(RenderNode, android.graphics.Rect, int) + * + * @hide + */ + public static final int STATUS_DREW = 0x4; + + private boolean mValid; + private final long mNativeDisplayList; + private HardwareRenderer mRenderer; + + private RenderNode(String name) { + mNativeDisplayList = nCreate(); + nSetDisplayListName(mNativeDisplayList, name); + } + + /** + * Creates a new display list that can be used to record batches of + * drawing operations. + * + * @param name The name of the display list, used for debugging purpose. May be null. + * + * @return A new display list. + * + * @hide + */ + public static RenderNode create(String name) { + return new RenderNode(name); + } + + /** + * Starts recording the display list. All operations performed on the + * returned canvas are recorded and stored in this display list. + * + * Calling this method will mark the display list invalid until + * {@link #end()} is called. Only valid display lists can be replayed. + * + * @param width The width of the display list's viewport + * @param height The height of the display list's viewport + * + * @return A canvas to record drawing operations. + * + * @see #end() + * @see #isValid() + */ + public HardwareCanvas start(int width, int height) { + HardwareCanvas canvas = GLES20RecordingCanvas.obtain(); + canvas.setViewport(width, height); + // The dirty rect should always be null for a display list + canvas.onPreDraw(null); + return canvas; + } + + /** + * Ends the recording for this display list. A display list cannot be + * replayed if recording is not finished. Calling this method marks + * the display list valid and {@link #isValid()} will return true. + * + * @see #start(int, int) + * @see #isValid() + */ + public void end(HardwareRenderer renderer, HardwareCanvas endCanvas) { + if (!(endCanvas instanceof GLES20RecordingCanvas)) { + throw new IllegalArgumentException("Passed an invalid canvas to end!"); + } + + GLES20RecordingCanvas canvas = (GLES20RecordingCanvas) endCanvas; + canvas.onPostDraw(); + long displayListData = canvas.finishRecording(); + if (renderer != mRenderer) { + // If we are changing renderers first destroy with the old + // renderer, then set with the new one + destroyDisplayListData(); + } + mRenderer = renderer; + setDisplayListData(displayListData); + canvas.recycle(); + mValid = true; + } + + /** + * Reset native resources. This is called when cleaning up the state of display lists + * during destruction of hardware resources, to ensure that we do not hold onto + * obsolete resources after related resources are gone. + * + * @hide + */ + public void destroyDisplayListData() { + if (!mValid) return; + + setDisplayListData(0); + mRenderer = null; + mValid = false; + } + + private void setDisplayListData(long newData) { + if (mRenderer != null) { + mRenderer.setDisplayListData(mNativeDisplayList, newData); + } else { + throw new IllegalStateException("Trying to set data without a renderer! data=" + newData); + } + } + + /** + * Returns whether the display list is currently usable. If this returns false, + * the display list should be re-recorded prior to replaying it. + * + * @return boolean true if the display list is able to be replayed, false otherwise. + */ + public boolean isValid() { return mValid; } + + long getNativeDisplayList() { + if (!mValid) { + throw new IllegalStateException("The display list is not valid."); + } + return mNativeDisplayList; + } + + /////////////////////////////////////////////////////////////////////////// + // DisplayList Property Setters + /////////////////////////////////////////////////////////////////////////// + + /** + * Set the caching property on the display list, which indicates whether the display list + * holds a layer. Layer display lists should avoid creating an alpha layer, since alpha is + * handled in the drawLayer operation directly (and more efficiently). + * + * @param caching true if the display list represents a hardware layer, false otherwise. + * + * @hide + */ + public void setCaching(boolean caching) { + nSetCaching(mNativeDisplayList, caching); + } + + /** + * Set whether the display list should clip itself to its bounds. This property is controlled by + * the view's parent. + * + * @param clipToBounds true if the display list should clip to its bounds + */ + public void setClipToBounds(boolean clipToBounds) { + nSetClipToBounds(mNativeDisplayList, clipToBounds); + } + + /** + * Set whether the display list should collect and Z order all 3d composited descendents, and + * draw them in order with the default Z=0 content. + * + * @param isolatedZVolume true if the display list should collect and Z order descendents. + */ + public void setIsolatedZVolume(boolean isolatedZVolume) { + nSetIsolatedZVolume(mNativeDisplayList, isolatedZVolume); + } + + /** + * Sets whether the display list should be drawn immediately after the + * closest ancestor display list where isolateZVolume is true. If the + * display list itself satisfies this constraint, changing this attribute + * has no effect on drawing order. + * + * @param shouldProject true if the display list should be projected onto a + * containing volume. + */ + public void setProjectBackwards(boolean shouldProject) { + nSetProjectBackwards(mNativeDisplayList, shouldProject); + } + + /** + * Sets whether the display list is a projection receiver - that its parent + * DisplayList should draw any descendent DisplayLists with + * ProjectBackwards=true directly on top of it. Default value is false. + */ + public void setProjectionReceiver(boolean shouldRecieve) { + nSetProjectionReceiver(mNativeDisplayList, shouldRecieve); + } + + /** + * Sets the outline, defining the shape that casts a shadow, and the path to + * be clipped if setClipToOutline is set. + * + * Deep copies the native path to simplify reference ownership. + * + * @param outline Convex, CW Path to store in the DisplayList. May be null. + */ + public void setOutline(Path outline) { + long nativePath = (outline == null) ? 0 : outline.mNativePath; + nSetOutline(mNativeDisplayList, nativePath); + } + + /** + * Enables or disables clipping to the outline. + * + * @param clipToOutline true if clipping to the outline. + */ + public void setClipToOutline(boolean clipToOutline) { + nSetClipToOutline(mNativeDisplayList, clipToOutline); + } + + /** + * Set whether the DisplayList should cast a shadow. + * + * The shape of the shadow casting area is defined by the outline of the display list, if set + * and non-empty, otherwise it will be the bounds rect. + */ + public void setCastsShadow(boolean castsShadow) { + nSetCastsShadow(mNativeDisplayList, castsShadow); + } + + /** + * Sets whether the DisplayList should be drawn with perspective applied from the global camera. + * + * If set to true, camera distance will be ignored. Defaults to false. + */ + public void setUsesGlobalCamera(boolean usesGlobalCamera) { + nSetUsesGlobalCamera(mNativeDisplayList, usesGlobalCamera); + } + + /** + * Set the static matrix on the display list. The specified matrix is combined with other + * transforms (such as {@link #setScaleX(float)}, {@link #setRotation(float)}, etc.) + * + * @param matrix A transform matrix to apply to this display list + * + * @see #getMatrix(android.graphics.Matrix) + * @see #getMatrix() + */ + public void setStaticMatrix(Matrix matrix) { + nSetStaticMatrix(mNativeDisplayList, matrix.native_instance); + } + + /** + * Set the Animation matrix on the display list. This matrix exists if an Animation is + * currently playing on a View, and is set on the display list during at draw() time. When + * the Animation finishes, the matrix should be cleared by sending <code>null</code> + * for the matrix parameter. + * + * @param matrix The matrix, null indicates that the matrix should be cleared. + * + * @hide + */ + public void setAnimationMatrix(Matrix matrix) { + nSetAnimationMatrix(mNativeDisplayList, + (matrix != null) ? matrix.native_instance : 0); + } + + /** + * Sets the translucency level for the display list. + * + * @param alpha The translucency of the display list, must be a value between 0.0f and 1.0f + * + * @see View#setAlpha(float) + * @see #getAlpha() + */ + public void setAlpha(float alpha) { + nSetAlpha(mNativeDisplayList, alpha); + } + + /** + * Returns the translucency level of this display list. + * + * @return A value between 0.0f and 1.0f + * + * @see #setAlpha(float) + */ + public float getAlpha() { + return nGetAlpha(mNativeDisplayList); + } + + /** + * Sets whether the display list renders content which overlaps. Non-overlapping rendering + * can use a fast path for alpha that avoids rendering to an offscreen buffer. By default + * display lists consider they do not have overlapping content. + * + * @param hasOverlappingRendering False if the content is guaranteed to be non-overlapping, + * true otherwise. + * + * @see android.view.View#hasOverlappingRendering() + * @see #hasOverlappingRendering() + */ + public void setHasOverlappingRendering(boolean hasOverlappingRendering) { + nSetHasOverlappingRendering(mNativeDisplayList, hasOverlappingRendering); + } + + /** + * Indicates whether the content of this display list overlaps. + * + * @return True if this display list renders content which overlaps, false otherwise. + * + * @see #setHasOverlappingRendering(boolean) + */ + public boolean hasOverlappingRendering() { + //noinspection SimplifiableIfStatement + return nHasOverlappingRendering(mNativeDisplayList); + } + + /** + * Sets the translation value for the display list on the X axis. + * + * @param translationX The X axis translation value of the display list, in pixels + * + * @see View#setTranslationX(float) + * @see #getTranslationX() + */ + public void setTranslationX(float translationX) { + nSetTranslationX(mNativeDisplayList, translationX); + } + + /** + * Returns the translation value for this display list on the X axis, in pixels. + * + * @see #setTranslationX(float) + */ + public float getTranslationX() { + return nGetTranslationX(mNativeDisplayList); + } + + /** + * Sets the translation value for the display list on the Y axis. + * + * @param translationY The Y axis translation value of the display list, in pixels + * + * @see View#setTranslationY(float) + * @see #getTranslationY() + */ + public void setTranslationY(float translationY) { + nSetTranslationY(mNativeDisplayList, translationY); + } + + /** + * Returns the translation value for this display list on the Y axis, in pixels. + * + * @see #setTranslationY(float) + */ + public float getTranslationY() { + return nGetTranslationY(mNativeDisplayList); + } + + /** + * Sets the translation value for the display list on the Z axis. + * + * @see View#setTranslationZ(float) + * @see #getTranslationZ() + */ + public void setTranslationZ(float translationZ) { + nSetTranslationZ(mNativeDisplayList, translationZ); + } + + /** + * Returns the translation value for this display list on the Z axis. + * + * @see #setTranslationZ(float) + */ + public float getTranslationZ() { + return nGetTranslationZ(mNativeDisplayList); + } + + /** + * Sets the rotation value for the display list around the Z axis. + * + * @param rotation The rotation value of the display list, in degrees + * + * @see View#setRotation(float) + * @see #getRotation() + */ + public void setRotation(float rotation) { + nSetRotation(mNativeDisplayList, rotation); + } + + /** + * Returns the rotation value for this display list around the Z axis, in degrees. + * + * @see #setRotation(float) + */ + public float getRotation() { + return nGetRotation(mNativeDisplayList); + } + + /** + * Sets the rotation value for the display list around the X axis. + * + * @param rotationX The rotation value of the display list, in degrees + * + * @see View#setRotationX(float) + * @see #getRotationX() + */ + public void setRotationX(float rotationX) { + nSetRotationX(mNativeDisplayList, rotationX); + } + + /** + * Returns the rotation value for this display list around the X axis, in degrees. + * + * @see #setRotationX(float) + */ + public float getRotationX() { + return nGetRotationX(mNativeDisplayList); + } + + /** + * Sets the rotation value for the display list around the Y axis. + * + * @param rotationY The rotation value of the display list, in degrees + * + * @see View#setRotationY(float) + * @see #getRotationY() + */ + public void setRotationY(float rotationY) { + nSetRotationY(mNativeDisplayList, rotationY); + } + + /** + * Returns the rotation value for this display list around the Y axis, in degrees. + * + * @see #setRotationY(float) + */ + public float getRotationY() { + return nGetRotationY(mNativeDisplayList); + } + + /** + * Sets the scale value for the display list on the X axis. + * + * @param scaleX The scale value of the display list + * + * @see View#setScaleX(float) + * @see #getScaleX() + */ + public void setScaleX(float scaleX) { + nSetScaleX(mNativeDisplayList, scaleX); + } + + /** + * Returns the scale value for this display list on the X axis. + * + * @see #setScaleX(float) + */ + public float getScaleX() { + return nGetScaleX(mNativeDisplayList); + } + + /** + * Sets the scale value for the display list on the Y axis. + * + * @param scaleY The scale value of the display list + * + * @see View#setScaleY(float) + * @see #getScaleY() + */ + public void setScaleY(float scaleY) { + nSetScaleY(mNativeDisplayList, scaleY); + } + + /** + * Returns the scale value for this display list on the Y axis. + * + * @see #setScaleY(float) + */ + public float getScaleY() { + return nGetScaleY(mNativeDisplayList); + } + + /** + * Sets all of the transform-related values of the display list + * + * @param alpha The alpha value of the display list + * @param translationX The translationX value of the display list + * @param translationY The translationY value of the display list + * @param rotation The rotation value of the display list + * @param rotationX The rotationX value of the display list + * @param rotationY The rotationY value of the display list + * @param scaleX The scaleX value of the display list + * @param scaleY The scaleY value of the display list + * + * @hide + */ + public void setTransformationInfo(float alpha, + float translationX, float translationY, float translationZ, + float rotation, float rotationX, float rotationY, float scaleX, float scaleY) { + nSetTransformationInfo(mNativeDisplayList, alpha, + translationX, translationY, translationZ, + rotation, rotationX, rotationY, scaleX, scaleY); + } + + /** + * Sets the pivot value for the display list on the X axis + * + * @param pivotX The pivot value of the display list on the X axis, in pixels + * + * @see View#setPivotX(float) + * @see #getPivotX() + */ + public void setPivotX(float pivotX) { + nSetPivotX(mNativeDisplayList, pivotX); + } + + /** + * Returns the pivot value for this display list on the X axis, in pixels. + * + * @see #setPivotX(float) + */ + public float getPivotX() { + return nGetPivotX(mNativeDisplayList); + } + + /** + * Sets the pivot value for the display list on the Y axis + * + * @param pivotY The pivot value of the display list on the Y axis, in pixels + * + * @see View#setPivotY(float) + * @see #getPivotY() + */ + public void setPivotY(float pivotY) { + nSetPivotY(mNativeDisplayList, pivotY); + } + + /** + * Returns the pivot value for this display list on the Y axis, in pixels. + * + * @see #setPivotY(float) + */ + public float getPivotY() { + return nGetPivotY(mNativeDisplayList); + } + + /** + * Sets the camera distance for the display list. Refer to + * {@link View#setCameraDistance(float)} for more information on how to + * use this property. + * + * @param distance The distance in Z of the camera of the display list + * + * @see View#setCameraDistance(float) + * @see #getCameraDistance() + */ + public void setCameraDistance(float distance) { + nSetCameraDistance(mNativeDisplayList, distance); + } + + /** + * Returns the distance in Z of the camera of the display list. + * + * @see #setCameraDistance(float) + */ + public float getCameraDistance() { + return nGetCameraDistance(mNativeDisplayList); + } + + /** + * Sets the left position for the display list. + * + * @param left The left position, in pixels, of the display list + * + * @see View#setLeft(int) + * @see #getLeft() + */ + public void setLeft(int left) { + nSetLeft(mNativeDisplayList, left); + } + + /** + * Returns the left position for the display list in pixels. + * + * @see #setLeft(int) + */ + public float getLeft() { + return nGetLeft(mNativeDisplayList); + } + + /** + * Sets the top position for the display list. + * + * @param top The top position, in pixels, of the display list + * + * @see View#setTop(int) + * @see #getTop() + */ + public void setTop(int top) { + nSetTop(mNativeDisplayList, top); + } + + /** + * Returns the top position for the display list in pixels. + * + * @see #setTop(int) + */ + public float getTop() { + return nGetTop(mNativeDisplayList); + } + + /** + * Sets the right position for the display list. + * + * @param right The right position, in pixels, of the display list + * + * @see View#setRight(int) + * @see #getRight() + */ + public void setRight(int right) { + nSetRight(mNativeDisplayList, right); + } + + /** + * Returns the right position for the display list in pixels. + * + * @see #setRight(int) + */ + public float getRight() { + return nGetRight(mNativeDisplayList); + } + + /** + * Sets the bottom position for the display list. + * + * @param bottom The bottom position, in pixels, of the display list + * + * @see View#setBottom(int) + * @see #getBottom() + */ + public void setBottom(int bottom) { + nSetBottom(mNativeDisplayList, bottom); + } + + /** + * Returns the bottom position for the display list in pixels. + * + * @see #setBottom(int) + */ + public float getBottom() { + return nGetBottom(mNativeDisplayList); + } + + /** + * Sets the left and top positions for the display list + * + * @param left The left position of the display list, in pixels + * @param top The top position of the display list, in pixels + * @param right The right position of the display list, in pixels + * @param bottom The bottom position of the display list, in pixels + * + * @see View#setLeft(int) + * @see View#setTop(int) + * @see View#setRight(int) + * @see View#setBottom(int) + */ + public void setLeftTopRightBottom(int left, int top, int right, int bottom) { + nSetLeftTopRightBottom(mNativeDisplayList, left, top, right, bottom); + } + + /** + * Offsets the left and right positions for the display list + * + * @param offset The amount that the left and right positions of the display + * list are offset, in pixels + * + * @see View#offsetLeftAndRight(int) + */ + public void offsetLeftAndRight(float offset) { + nOffsetLeftAndRight(mNativeDisplayList, offset); + } + + /** + * Offsets the top and bottom values for the display list + * + * @param offset The amount that the top and bottom positions of the display + * list are offset, in pixels + * + * @see View#offsetTopAndBottom(int) + */ + public void offsetTopAndBottom(float offset) { + nOffsetTopAndBottom(mNativeDisplayList, offset); + } + + /** + * Outputs the display list to the log. This method exists for use by + * tools to output display lists for selected nodes to the log. + * + * @hide + */ + public void output() { + nOutput(mNativeDisplayList); + } + + /////////////////////////////////////////////////////////////////////////// + // Native methods + /////////////////////////////////////////////////////////////////////////// + + private static native long nCreate(); + private static native void nDestroyDisplayList(long displayList); + private static native void nSetDisplayListName(long displayList, String name); + + // Properties + + private static native void nOffsetTopAndBottom(long displayList, float offset); + private static native void nOffsetLeftAndRight(long displayList, float offset); + private static native void nSetLeftTopRightBottom(long displayList, int left, int top, + int right, int bottom); + private static native void nSetBottom(long displayList, int bottom); + private static native void nSetRight(long displayList, int right); + private static native void nSetTop(long displayList, int top); + private static native void nSetLeft(long displayList, int left); + private static native void nSetCameraDistance(long displayList, float distance); + private static native void nSetPivotY(long displayList, float pivotY); + private static native void nSetPivotX(long displayList, float pivotX); + private static native void nSetCaching(long displayList, boolean caching); + private static native void nSetClipToBounds(long displayList, boolean clipToBounds); + private static native void nSetProjectBackwards(long displayList, boolean shouldProject); + private static native void nSetProjectionReceiver(long displayList, boolean shouldRecieve); + private static native void nSetIsolatedZVolume(long displayList, boolean isolateZVolume); + 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 nSetUsesGlobalCamera(long displayList, boolean usesGlobalCamera); + private static native void nSetAlpha(long displayList, float alpha); + private static native void nSetHasOverlappingRendering(long displayList, + boolean hasOverlappingRendering); + private static native void nSetTranslationX(long displayList, float translationX); + private static native void nSetTranslationY(long displayList, float translationY); + private static native void nSetTranslationZ(long displayList, float translationZ); + private static native void nSetRotation(long displayList, float rotation); + private static native void nSetRotationX(long displayList, float rotationX); + private static native void nSetRotationY(long displayList, float rotationY); + private static native void nSetScaleX(long displayList, float scaleX); + private static native void nSetScaleY(long displayList, float scaleY); + private static native void nSetTransformationInfo(long displayList, float alpha, + float translationX, float translationY, float translationZ, + float rotation, float rotationX, float rotationY, float scaleX, float scaleY); + private static native void nSetStaticMatrix(long displayList, long nativeMatrix); + private static native void nSetAnimationMatrix(long displayList, long animationMatrix); + + private static native boolean nHasOverlappingRendering(long displayList); + private static native float nGetAlpha(long displayList); + private static native float nGetLeft(long displayList); + private static native float nGetTop(long displayList); + private static native float nGetRight(long displayList); + private static native float nGetBottom(long displayList); + private static native float nGetCameraDistance(long displayList); + private static native float nGetScaleX(long displayList); + private static native float nGetScaleY(long displayList); + private static native float nGetTranslationX(long displayList); + private static native float nGetTranslationY(long displayList); + private static native float nGetTranslationZ(long displayList); + private static native float nGetRotation(long displayList); + private static native float nGetRotationX(long displayList); + private static native float nGetRotationY(long displayList); + private static native float nGetPivotX(long displayList); + private static native float nGetPivotY(long displayList); + private static native void nOutput(long displayList); + + /////////////////////////////////////////////////////////////////////////// + // Finalization + /////////////////////////////////////////////////////////////////////////// + + @Override + protected void finalize() throws Throwable { + try { + destroyDisplayListData(); + nDestroyDisplayList(mNativeDisplayList); + } finally { + super.finalize(); + } + } +} diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index a1fb123..2a488a0 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -163,7 +163,7 @@ public class ThreadedRenderer extends HardwareRenderer { view.mPrivateFlags &= ~View.PFLAG_INVALIDATED; Trace.traceBegin(Trace.TRACE_TAG_VIEW, "getDisplayList"); - DisplayList displayList = view.getDisplayList(); + RenderNode displayList = view.getDisplayList(); Trace.traceEnd(Trace.TRACE_TAG_VIEW); view.mRecreateDisplayList = false; diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d72f810..eff78d3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3269,7 +3269,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * of the background drawable. It is cleared on temporary detach and reset * on cleanup. */ - private DisplayList mBackgroundDisplayList; + private RenderNode mBackgroundDisplayList; private int mBackgroundResource; private boolean mBackgroundSizeChanged; @@ -3559,7 +3559,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * of the View content. It is cleared on temporary detach and reset on * cleanup. */ - DisplayList mDisplayList; + RenderNode mDisplayList; /** * Set to true when the view is sending hover accessibility events because it @@ -13802,7 +13802,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } mHardwareLayer.setLayerPaint(mLayerPaint); - DisplayList displayList = mHardwareLayer.startRecording(); + RenderNode displayList = mHardwareLayer.startRecording(); if (getDisplayList(displayList, true) != displayList) { throw new IllegalStateException("getDisplayList() didn't return" + " the input displaylist for a hardware layer!"); @@ -13952,8 +13952,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * the view will avoid creating a layer inside the resulting display list. * @return A new or reused DisplayList object. */ - private DisplayList getDisplayList(DisplayList displayList, boolean isLayer) { - if (!canHaveDisplayList()) { + private RenderNode getDisplayList(RenderNode displayList, boolean isLayer) { + final HardwareRenderer renderer = getHardwareRenderer(); + if (renderer == null || !canHaveDisplayList()) { return null; } @@ -13977,7 +13978,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mRecreateDisplayList = true; } if (displayList == null) { - displayList = DisplayList.create(getClass().getName()); + displayList = RenderNode.create(getClass().getName()); // If we're creating a new display list, make sure our parent gets invalidated // since they will need to recreate their display list to account for this // new child display list. @@ -14032,13 +14033,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } } finally { - displayList.end(getHardwareRenderer(), canvas); + displayList.end(renderer, canvas); displayList.setCaching(caching); if (isLayer) { displayList.setLeftTopRightBottom(0, 0, width, height); } else { setDisplayListProperties(displayList); } + + if (renderer != getHardwareRenderer()) { + Log.w(VIEW_LOG_TAG, "View was detached during a draw() call!"); + // TODO: Should this be elevated to a crash? + // For now have it behaves the same as it previously did, it + // will result in the DisplayListData being destroyed later + // than it could be but oh well... + } } } else if (!isLayer) { mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; @@ -14056,7 +14065,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ - public DisplayList getDisplayList() { + public RenderNode getDisplayList() { mDisplayList = getDisplayList(mDisplayList, false); return mDisplayList; } @@ -14662,7 +14671,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * necessary when a display list is being re-created, because we need to make sure that * previously-set transform values */ - void setDisplayListProperties(DisplayList displayList) { + void setDisplayListProperties(RenderNode displayList) { if (displayList != null) { displayList.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); displayList.setHasOverlappingRendering(hasOverlappingRendering()); @@ -14807,7 +14816,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags &= ~PFLAG_INVALIDATED; } - DisplayList displayList = null; + RenderNode displayList = null; Bitmap cache = null; boolean hasDisplayList = false; if (caching) { @@ -15286,7 +15295,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, && mAttachInfo.mHardwareRenderer != null) { mBackgroundDisplayList = getDrawableDisplayList(background, mBackgroundDisplayList); - final DisplayList displayList = mBackgroundDisplayList; + final RenderNode displayList = mBackgroundDisplayList; if (displayList != null && displayList.isValid()) { setBackgroundDisplayListProperties(displayList); ((HardwareCanvas) canvas).drawDisplayList(displayList); @@ -15310,7 +15319,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param displayList Valid display list for the background drawable */ - private void setBackgroundDisplayListProperties(DisplayList displayList) { + private void setBackgroundDisplayListProperties(RenderNode displayList) { displayList.setTranslationX(mScrollX); displayList.setTranslationY(mScrollY); } @@ -15323,9 +15332,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @param displayList Existing display list, or {@code null} * @return A valid display list for the specified drawable */ - private DisplayList getDrawableDisplayList(Drawable drawable, DisplayList displayList) { + private RenderNode getDrawableDisplayList(Drawable drawable, RenderNode displayList) { if (displayList == null) { - displayList = DisplayList.create(drawable.getClass().getName()); + displayList = RenderNode.create(drawable.getClass().getName()); } final Rect bounds = drawable.getBounds(); diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java index 1892aa7..563ffb7 100644 --- a/core/java/android/view/ViewPropertyAnimator.java +++ b/core/java/android/view/ViewPropertyAnimator.java @@ -925,7 +925,7 @@ public class ViewPropertyAnimator { */ private void setValue(int propertyConstant, float value) { final View.TransformationInfo info = mView.mTransformationInfo; - final DisplayList displayList = mView.mDisplayList; + final RenderNode displayList = mView.mDisplayList; switch (propertyConstant) { case TRANSLATION_X: info.mTranslationX = value; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 18517c5..185cb65 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1465,7 +1465,7 @@ public final class ViewRootImpl implements ViewParent, mWidth, mHeight); } mResizeBuffer.prepare(mWidth, mHeight, false); - DisplayList layerDisplayList = mResizeBuffer.startRecording(); + RenderNode layerDisplayList = mResizeBuffer.startRecording(); HardwareCanvas layerCanvas = layerDisplayList.start(mWidth, mHeight); final int restoreCount = layerCanvas.save(); @@ -1484,10 +1484,10 @@ public final class ViewRootImpl implements ViewParent, mTranslator.translateCanvas(layerCanvas); } - DisplayList displayList = mView.mDisplayList; + RenderNode displayList = mView.mDisplayList; if (displayList != null && displayList.isValid()) { layerCanvas.drawDisplayList(displayList, null, - DisplayList.FLAG_CLIP_CHILDREN); + RenderNode.FLAG_CLIP_CHILDREN); } else { mView.draw(layerCanvas); } @@ -2178,7 +2178,7 @@ public final class ViewRootImpl implements ViewParent, * @hide */ void outputDisplayList(View view) { - DisplayList displayList = view.getDisplayList(); + RenderNode displayList = view.getDisplayList(); if (displayList != null) { displayList.output(); } @@ -5206,7 +5206,7 @@ public final class ViewRootImpl implements ViewParent, } private static void getGfxInfo(View view, int[] info) { - DisplayList displayList = view.mDisplayList; + RenderNode displayList = view.mDisplayList; info[0]++; if (displayList != null) { info[1] += 0; /* TODO: Memory used by display lists */ diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 53d9e28..333e631 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -74,7 +74,7 @@ import android.util.DisplayMetrics; import android.util.Log; import android.view.ActionMode; import android.view.ActionMode.Callback; -import android.view.DisplayList; +import android.view.RenderNode; import android.view.DragEvent; import android.view.Gravity; import android.view.HardwareCanvas; @@ -138,11 +138,11 @@ public class Editor { InputMethodState mInputMethodState; private static class TextDisplayList { - DisplayList displayList; + RenderNode displayList; boolean isDirty; public TextDisplayList(String name) { isDirty = true; - displayList = DisplayList.create(name); + displayList = RenderNode.create(name); } boolean needsRecord() { return isDirty || !displayList.isValid(); } } @@ -289,7 +289,7 @@ public class Editor { private void destroyDisplayListsData() { if (mTextDisplayLists != null) { for (int i = 0; i < mTextDisplayLists.length; i++) { - DisplayList displayList = mTextDisplayLists[i] != null + RenderNode displayList = mTextDisplayLists[i] != null ? mTextDisplayLists[i].displayList : null; if (displayList != null && displayList.isValid()) { displayList.destroyDisplayListData(); @@ -1371,7 +1371,7 @@ public class Editor { } final boolean blockDisplayListIsInvalid = mTextDisplayLists[blockIndex].needsRecord(); - DisplayList blockDisplayList = mTextDisplayLists[blockIndex].displayList; + RenderNode blockDisplayList = mTextDisplayLists[blockIndex].displayList; if (i >= indexFirstChangedBlock || blockDisplayListIsInvalid) { final int blockBeginLine = endOfPreviousBlock + 1; final int top = layout.getLineTop(blockBeginLine); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 10fd2f0..26d7f5f 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -270,7 +270,6 @@ public final class BatteryStatsImpl extends BatteryStats { boolean mWifiOn; StopwatchTimer mWifiOnTimer; - int mWifiOnUid = -1; boolean mGlobalWifiRunning; StopwatchTimer mGlobalWifiRunningTimer; @@ -2912,10 +2911,6 @@ public final class BatteryStatsImpl extends BatteryStats { mWifiOn = false; mWifiOnTimer.stopRunningLocked(elapsedRealtime); } - if (mWifiOnUid >= 0) { - getUidStatsLocked(mWifiOnUid).noteWifiStoppedLocked(elapsedRealtime); - mWifiOnUid = -1; - } } public void noteAudioOnLocked(int uid) { @@ -5973,7 +5968,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (entry.rxBytes == 0 || entry.txBytes == 0) continue; - final Uid u = getUidStatsLocked(entry.uid); + final Uid u = getUidStatsLocked(mapUid(entry.uid)); u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes, entry.rxPackets); u.noteNetworkActivityLocked(NETWORK_MOBILE_TX_DATA, entry.txBytes, @@ -6040,7 +6035,7 @@ public final class BatteryStatsImpl extends BatteryStats { if (entry.rxBytes == 0 || entry.txBytes == 0) continue; - final Uid u = getUidStatsLocked(entry.uid); + final Uid u = getUidStatsLocked(mapUid(entry.uid)); u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes, entry.rxPackets); u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes, @@ -6240,6 +6235,7 @@ public final class BatteryStatsImpl extends BatteryStats { * if needed. */ public Uid.Proc getProcessStatsLocked(int uid, String name) { + uid = mapUid(uid); Uid u = getUidStatsLocked(uid); return u.getProcessStatsLocked(name); } @@ -6249,6 +6245,7 @@ public final class BatteryStatsImpl extends BatteryStats { * if needed. */ public Uid.Pkg getPackageStatsLocked(int uid, String pkg) { + uid = mapUid(uid); Uid u = getUidStatsLocked(uid); return u.getPackageStatsLocked(pkg); } @@ -6258,6 +6255,7 @@ public final class BatteryStatsImpl extends BatteryStats { * if needed. */ public Uid.Pkg.Serv getServiceStatsLocked(int uid, String pkg, String name) { + uid = mapUid(uid); Uid u = getUidStatsLocked(uid); return u.getServiceStatsLocked(pkg, name); } diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 97ea7d8..4734712 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -41,11 +41,11 @@ interface IStatusBarService out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications, out int[] switches, out List<IBinder> binders); void onPanelRevealed(); - void onNotificationClick(String pkg, String tag, int id); + void onNotificationClick(String pkg, String tag, int id, int userId); void onNotificationError(String pkg, String tag, int id, - int uid, int initialPid, String message); - void onClearAllNotifications(); - void onNotificationClear(String pkg, String tag, int id); + int uid, int initialPid, String message, int userId); + void onClearAllNotifications(int userId); + void onNotificationClear(String pkg, String tag, int id, int userId); void setSystemUiVisibility(int vis, int mask); void setHardKeyboardEnabled(boolean enabled); void toggleRecentApps(); diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java index 26235f1..71550be 100644 --- a/core/java/com/android/internal/util/FileRotator.java +++ b/core/java/com/android/internal/util/FileRotator.java @@ -336,7 +336,12 @@ public class FileRotator { final long deleteBefore = currentTimeMillis - mDeleteAgeMillis; final FileInfo info = new FileInfo(mPrefix); - for (String name : mBasePath.list()) { + String[] baseFiles = mBasePath.list(); + if (baseFiles == null) { + return; + } + + for (String name : baseFiles) { if (!info.parse(name)) continue; if (info.isActive()) { diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index e51345c..45ca7fc 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -75,7 +75,7 @@ interface IInputMethodManager { boolean switchToNextInputMethod(in IBinder token, boolean onlyCurrentIme); boolean shouldOfferSwitchingToNextInputMethod(in IBinder token); boolean setInputMethodEnabled(String id, boolean enabled); - oneway void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); + void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); int getInputMethodWindowVisibleHeight(); oneway void notifyTextCommitted(); } diff --git a/core/jni/Android.mk b/core/jni/Android.mk index a09c314..51c5a86 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -42,7 +42,6 @@ LOCAL_SRC_FILES:= \ android_database_SQLiteDebug.cpp \ android_emoji_EmojiFactory.cpp \ android_view_DisplayEventReceiver.cpp \ - android_view_DisplayList.cpp \ android_view_Surface.cpp \ android_view_SurfaceControl.cpp \ android_view_SurfaceSession.cpp \ @@ -61,6 +60,7 @@ LOCAL_SRC_FILES:= \ android_view_ThreadedRenderer.cpp \ android_view_MotionEvent.cpp \ android_view_PointerIcon.cpp \ + android_view_RenderNode.cpp \ android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 94c3f44..9a7a5f9 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -119,7 +119,7 @@ extern int register_android_graphics_SurfaceTexture(JNIEnv* env); extern int register_android_graphics_Xfermode(JNIEnv* env); extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env); extern int register_android_view_DisplayEventReceiver(JNIEnv* env); -extern int register_android_view_DisplayList(JNIEnv* env); +extern int register_android_view_RenderNode(JNIEnv* env); extern int register_android_view_GraphicBuffer(JNIEnv* env); extern int register_android_view_GLES20Canvas(JNIEnv* env); extern int register_android_view_GLRenderer(JNIEnv* env); @@ -435,6 +435,14 @@ void AndroidRuntime::parseExtraOpts(char* extraOptsBuf, const char* quotingArg) * Various arguments, most determined by system properties, are passed in. * The "mOptions" vector is updated. * + * CAUTION: when adding options in here, be careful not to put the + * char buffer inside a nested scope. Adding the buffer to the + * options using mOptions.add() does not copy the buffer, so if the + * buffer goes out of scope the option may be overwritten. It's best + * to put the buffer at the top of the function so that it is more + * unlikely that someone will surround it in a scope at a later time + * and thus introduce a bug. + * * Returns 0 on success. */ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) @@ -469,7 +477,15 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) kEMIntFast, kEMJitCompiler, } executionMode = kEMDefault; - + char profile_period[sizeof("-Xprofile-period:") + PROPERTY_VALUE_MAX]; + char profile_duration[sizeof("-Xprofile-duration:") + PROPERTY_VALUE_MAX]; + char profile_interval[sizeof("-Xprofile-interval:") + PROPERTY_VALUE_MAX]; + char profile_backoff[sizeof("-Xprofile-backoff:") + PROPERTY_VALUE_MAX]; + char langOption[sizeof("-Duser.language=") + 3]; + char regionOption[sizeof("-Duser.region=") + 3]; + char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)]; + char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX]; + char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX]; property_get("dalvik.vm.checkjni", propBuf, ""); if (strcmp(propBuf, "true") == 0) { @@ -670,7 +686,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) //mOptions.add(opt); } - char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)]; property_get("dalvik.vm.lockprof.threshold", propBuf, ""); if (strlen(propBuf) > 0) { strcpy(lockProfThresholdBuf, "-Xlockprofthreshold:"); @@ -680,7 +695,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) } /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */ - char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX]; property_get("dalvik.vm.jit.op", propBuf, ""); if (strlen(propBuf) > 0) { strcpy(jitOpBuf, "-Xjitop:"); @@ -690,7 +704,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) } /* Force interpreter-only mode for selected methods */ - char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX]; property_get("dalvik.vm.jit.method", propBuf, ""); if (strlen(propBuf) > 0) { strcpy(jitMethodBuf, "-Xjitmethod:"); @@ -770,8 +783,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) /* Set the properties for locale */ { - char langOption[sizeof("-Duser.language=") + 3]; - char regionOption[sizeof("-Duser.region=") + 3]; strcpy(langOption, "-Duser.language="); strcpy(regionOption, "-Duser.region="); readLocale(langOption, regionOption); @@ -786,35 +797,30 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv) * Set profiler options */ if (libart) { - char period[sizeof("-Xprofile-period:") + PROPERTY_VALUE_MAX]; - char duration[sizeof("-Xprofile-duration:") + PROPERTY_VALUE_MAX]; - char interval[sizeof("-Xprofile-interval:") + PROPERTY_VALUE_MAX]; - char backoff[sizeof("-Xprofile-backoff:") + PROPERTY_VALUE_MAX]; - // Number of seconds during profile runs. - strcpy(period, "-Xprofile-period:"); - property_get("dalvik.vm.profile.period_secs", period+17, "10"); - opt.optionString = period; + strcpy(profile_period, "-Xprofile-period:"); + property_get("dalvik.vm.profile.period_secs", profile_period+17, "10"); + opt.optionString = profile_period; mOptions.add(opt); // Length of each profile run (seconds). - strcpy(duration, "-Xprofile-duration:"); - property_get("dalvik.vm.profile.duration_secs", duration+19, "30"); - opt.optionString = duration; + strcpy(profile_duration, "-Xprofile-duration:"); + property_get("dalvik.vm.profile.duration_secs", profile_duration+19, "30"); + opt.optionString = profile_duration; mOptions.add(opt); // Polling interval during profile run (microseconds). - strcpy(interval, "-Xprofile-interval:"); - property_get("dalvik.vm.profile.interval_us", interval+19, "10000"); - opt.optionString = interval; + strcpy(profile_interval, "-Xprofile-interval:"); + property_get("dalvik.vm.profile.interval_us", profile_interval+19, "10000"); + opt.optionString = profile_interval; mOptions.add(opt); // Coefficient for period backoff. The the period is multiplied // by this value after each profile run. - strcpy(backoff, "-Xprofile-backoff:"); - property_get("dalvik.vm.profile.backoff_coeff", backoff+18, "2.0"); - opt.optionString = backoff; + strcpy(profile_backoff, "-Xprofile-backoff:"); + property_get("dalvik.vm.profile.backoff_coeff", profile_backoff+18, "2.0"); + opt.optionString = profile_backoff; mOptions.add(opt); } @@ -1173,7 +1179,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_nio_utils), REG_JNI(register_android_graphics_Graphics), REG_JNI(register_android_view_DisplayEventReceiver), - REG_JNI(register_android_view_DisplayList), + REG_JNI(register_android_view_RenderNode), REG_JNI(register_android_view_GraphicBuffer), REG_JNI(register_android_view_GLES20Canvas), REG_JNI(register_android_view_GLRenderer), diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index 3c7da1e..8c15ac2 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -19,13 +19,18 @@ // #define LOG_NNDEBUG 0 #define LOG_TAG "CameraMetadata-JNI" #include <utils/Log.h> +#include <utils/RefBase.h> +#include <string.h> #include "jni.h" #include "JNIHelp.h" #include "android_os_Parcel.h" #include "android_runtime/AndroidRuntime.h" +#include <binder/IServiceManager.h> #include <camera/CameraMetadata.h> +#include <camera/ICameraService.h> +#include <camera/VendorTagDescriptor.h> #include <nativehelper/ScopedUtfChars.h> #include <nativehelper/ScopedPrimitiveArray.h> @@ -112,6 +117,7 @@ extern "C" { static void CameraMetadata_classInit(JNIEnv *env, jobject thiz); static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyName); static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag); +static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz); // Less safe access to native pointer. Does NOT throw any Java exceptions if NULL. static CameraMetadata* CameraMetadata_getPointerNoThrow(JNIEnv *env, jobject thiz) { @@ -372,6 +378,9 @@ static JNINativeMethod gCameraMetadataMethods[] = { { "nativeGetTypeFromTag", "(I)I", (void *)CameraMetadata_getTypeFromTag }, + { "nativeSetupGlobalVendorTagDescriptor", + "()I", + (void*)CameraMetadata_setupGlobalVendorTagDescriptor }, // instance methods { "nativeAllocate", "()J", @@ -556,4 +565,29 @@ static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) { return tagType; } +static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) { + const String16 NAME("media.camera"); + sp<ICameraService> cameraService; + status_t err = getService(NAME, /*out*/&cameraService); + + if (err != OK) { + ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__, + strerror(-err), err); + return err; + } + + sp<VendorTagDescriptor> desc; + err = cameraService->getCameraVendorTagDescriptor(/*out*/desc); + + if (err != OK) { + ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)", __FUNCTION__, + strerror(-err), err); + return err; + } + + err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc); + + return err; +} + } // extern "C" diff --git a/core/jni/android_view_DisplayList.cpp b/core/jni/android_view_DisplayList.cpp deleted file mode 100644 index c8952c1..0000000 --- a/core/jni/android_view_DisplayList.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "OpenGLRenderer" - -#include <EGL/egl.h> - -#include "jni.h" -#include "GraphicsJNI.h" -#include <nativehelper/JNIHelp.h> -#include <android_runtime/AndroidRuntime.h> - -#include <DisplayList.h> -#include <DisplayListRenderer.h> - -namespace android { - -using namespace uirenderer; - -/** - * Note: OpenGLRenderer JNI layer is generated and compiled only on supported - * devices. This means all the logic must be compiled only when the - * preprocessor variable USE_OPENGL_RENDERER is defined. - */ -#ifdef USE_OPENGL_RENDERER - -// ---------------------------------------------------------------------------- -// DisplayList view properties -// ---------------------------------------------------------------------------- - -static void android_view_DisplayList_setDisplayListName(JNIEnv* env, - jobject clazz, jlong displayListPtr, jstring name) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - if (name != NULL) { - const char* textArray = env->GetStringUTFChars(name, NULL); - displayList->setName(textArray); - env->ReleaseStringUTFChars(name, textArray); - } -} - -static void android_view_DisplayList_output(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->output(); -} - -static jlong android_view_DisplayList_create(JNIEnv* env, jobject clazz) { - DisplayList* displayList = new DisplayList(); - return reinterpret_cast<jlong>(displayList); -} - -static void android_view_DisplayList_destroyDisplayList(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - DisplayList::destroyDisplayListDeferred(displayList); -} - -// ---------------------------------------------------------------------------- -// DisplayList view properties -// ---------------------------------------------------------------------------- - -static void android_view_DisplayList_setCaching(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean caching) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setCaching(caching); -} - -static void android_view_DisplayList_setStaticMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong matrixPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - displayList->setStaticMatrix(matrix); -} - -static void android_view_DisplayList_setAnimationMatrix(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong matrixPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); - displayList->setAnimationMatrix(matrix); -} - -static void android_view_DisplayList_setClipToBounds(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean clipToBounds) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setClipToBounds(clipToBounds); -} - -static void android_view_DisplayList_setIsolatedZVolume(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean shouldIsolate) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setIsolatedZVolume(shouldIsolate); -} - -static void android_view_DisplayList_setProjectBackwards(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean shouldProject) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setProjectBackwards(shouldProject); -} - -static void android_view_DisplayList_setProjectionReceiver(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean shouldRecieve) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setProjectionReceiver(shouldRecieve); -} - -static void android_view_DisplayList_setOutline(JNIEnv* env, - jobject clazz, jlong displayListPtr, jlong outlinePathPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - SkPath* outline = reinterpret_cast<SkPath*>(outlinePathPtr); - displayList->setOutline(outline); -} - -static void android_view_DisplayList_setClipToOutline(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean clipToOutline) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setClipToOutline(clipToOutline); -} - -static void android_view_DisplayList_setCastsShadow(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean castsShadow) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setCastsShadow(castsShadow); -} - -static void android_view_DisplayList_setUsesGlobalCamera(JNIEnv* env, - jobject clazz, jlong displayListPtr, jboolean usesGlobalCamera) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setUsesGlobalCamera(usesGlobalCamera); -} - -static void android_view_DisplayList_setAlpha(JNIEnv* env, - jobject clazz, jlong displayListPtr, float alpha) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setAlpha(alpha); -} - -static void android_view_DisplayList_setHasOverlappingRendering(JNIEnv* env, - jobject clazz, jlong displayListPtr, bool hasOverlappingRendering) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setHasOverlappingRendering(hasOverlappingRendering); -} - -static void android_view_DisplayList_setTranslationX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float tx) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setTranslationX(tx); -} - -static void android_view_DisplayList_setTranslationY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float ty) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setTranslationY(ty); -} - -static void android_view_DisplayList_setTranslationZ(JNIEnv* env, - jobject clazz, jlong displayListPtr, float tz) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setTranslationZ(tz); -} - -static void android_view_DisplayList_setRotation(JNIEnv* env, - jobject clazz, jlong displayListPtr, float rotation) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setRotation(rotation); -} - -static void android_view_DisplayList_setRotationX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float rx) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setRotationX(rx); -} - -static void android_view_DisplayList_setRotationY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float ry) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setRotationY(ry); -} - -static void android_view_DisplayList_setScaleX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float sx) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setScaleX(sx); -} - -static void android_view_DisplayList_setScaleY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float sy) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setScaleY(sy); -} - -static void android_view_DisplayList_setTransformationInfo(JNIEnv* env, - jobject clazz, jlong displayListPtr, float alpha, - float translationX, float translationY, float translationZ, - float rotation, float rotationX, float rotationY, float scaleX, float scaleY) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setAlpha(alpha); - displayList->setTranslationX(translationX); - displayList->setTranslationY(translationY); - displayList->setTranslationZ(translationZ); - displayList->setRotation(rotation); - displayList->setRotationX(rotationX); - displayList->setRotationY(rotationY); - displayList->setScaleX(scaleX); - displayList->setScaleY(scaleY); -} - -static void android_view_DisplayList_setPivotX(JNIEnv* env, - jobject clazz, jlong displayListPtr, float px) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setPivotX(px); -} - -static void android_view_DisplayList_setPivotY(JNIEnv* env, - jobject clazz, jlong displayListPtr, float py) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setPivotY(py); -} - -static void android_view_DisplayList_setCameraDistance(JNIEnv* env, - jobject clazz, jlong displayListPtr, float distance) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setCameraDistance(distance); -} - -static void android_view_DisplayList_setLeft(JNIEnv* env, - jobject clazz, jlong displayListPtr, int left) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setLeft(left); -} - -static void android_view_DisplayList_setTop(JNIEnv* env, - jobject clazz, jlong displayListPtr, int top) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setTop(top); -} - -static void android_view_DisplayList_setRight(JNIEnv* env, - jobject clazz, jlong displayListPtr, int right) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setRight(right); -} - -static void android_view_DisplayList_setBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr, int bottom) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setBottom(bottom); -} - -static void android_view_DisplayList_setLeftTopRightBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr, int left, int top, - int right, int bottom) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->setLeftTopRightBottom(left, top, right, bottom); -} - -static void android_view_DisplayList_offsetLeftAndRight(JNIEnv* env, - jobject clazz, jlong displayListPtr, float offset) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->offsetLeftRight(offset); -} - -static void android_view_DisplayList_offsetTopAndBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr, float offset) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - displayList->offsetTopBottom(offset); -} - -static jboolean android_view_DisplayList_hasOverlappingRendering(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->hasOverlappingRendering(); -} - -static jfloat android_view_DisplayList_getAlpha(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getAlpha(); -} - -static jfloat android_view_DisplayList_getLeft(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getLeft(); -} - -static jfloat android_view_DisplayList_getTop(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getTop(); -} - -static jfloat android_view_DisplayList_getRight(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getRight(); -} - -static jfloat android_view_DisplayList_getBottom(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getBottom(); -} - -static jfloat android_view_DisplayList_getCameraDistance(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getCameraDistance(); -} - -static jfloat android_view_DisplayList_getScaleX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getScaleX(); -} - -static jfloat android_view_DisplayList_getScaleY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getScaleY(); -} - -static jfloat android_view_DisplayList_getTranslationX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getTranslationX(); -} - -static jfloat android_view_DisplayList_getTranslationY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getTranslationY(); -} - -static jfloat android_view_DisplayList_getRotation(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getRotation(); -} - -static jfloat android_view_DisplayList_getRotationX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getRotationX(); -} - -static jfloat android_view_DisplayList_getRotationY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getRotationY(); -} - -static jfloat android_view_DisplayList_getPivotX(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getPivotX(); -} - -static jfloat android_view_DisplayList_getPivotY(JNIEnv* env, - jobject clazz, jlong displayListPtr) { - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); - return displayList->getPivotY(); -} - -#endif // USE_OPENGL_RENDERER - -// ---------------------------------------------------------------------------- -// JNI Glue -// ---------------------------------------------------------------------------- - -const char* const kClassPathName = "android/view/DisplayList"; - -static JNINativeMethod gMethods[] = { -#ifdef USE_OPENGL_RENDERER - { "nCreate", "()J", (void*) android_view_DisplayList_create }, - { "nDestroyDisplayList", "(J)V", (void*) android_view_DisplayList_destroyDisplayList }, - { "nSetDisplayListName", "(JLjava/lang/String;)V", - (void*) android_view_DisplayList_setDisplayListName }, - { "nOutput", "(J)V", (void*) android_view_DisplayList_output }, - - { "nSetCaching", "(JZ)V", (void*) android_view_DisplayList_setCaching }, - { "nSetStaticMatrix", "(JJ)V", (void*) android_view_DisplayList_setStaticMatrix }, - { "nSetAnimationMatrix", "(JJ)V", (void*) android_view_DisplayList_setAnimationMatrix }, - { "nSetClipToBounds", "(JZ)V", (void*) android_view_DisplayList_setClipToBounds }, - { "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_DisplayList_setIsolatedZVolume }, - { "nSetProjectBackwards", "(JZ)V", (void*) android_view_DisplayList_setProjectBackwards }, - { "nSetProjectionReceiver","(JZ)V", (void*) android_view_DisplayList_setProjectionReceiver }, - { "nSetOutline", "(JJ)V", (void*) android_view_DisplayList_setOutline }, - { "nSetClipToOutline", "(JZ)V", (void*) android_view_DisplayList_setClipToOutline }, - { "nSetCastsShadow", "(JZ)V", (void*) android_view_DisplayList_setCastsShadow }, - { "nSetUsesGlobalCamera", "(JZ)V", (void*) android_view_DisplayList_setUsesGlobalCamera }, - { "nSetAlpha", "(JF)V", (void*) android_view_DisplayList_setAlpha }, - { "nSetHasOverlappingRendering", "(JZ)V", - (void*) android_view_DisplayList_setHasOverlappingRendering }, - { "nSetTranslationX", "(JF)V", (void*) android_view_DisplayList_setTranslationX }, - { "nSetTranslationY", "(JF)V", (void*) android_view_DisplayList_setTranslationY }, - { "nSetTranslationZ", "(JF)V", (void*) android_view_DisplayList_setTranslationZ }, - { "nSetRotation", "(JF)V", (void*) android_view_DisplayList_setRotation }, - { "nSetRotationX", "(JF)V", (void*) android_view_DisplayList_setRotationX }, - { "nSetRotationY", "(JF)V", (void*) android_view_DisplayList_setRotationY }, - { "nSetScaleX", "(JF)V", (void*) android_view_DisplayList_setScaleX }, - { "nSetScaleY", "(JF)V", (void*) android_view_DisplayList_setScaleY }, - { "nSetTransformationInfo","(JFFFFFFFFF)V", - (void*) android_view_DisplayList_setTransformationInfo }, - { "nSetPivotX", "(JF)V", (void*) android_view_DisplayList_setPivotX }, - { "nSetPivotY", "(JF)V", (void*) android_view_DisplayList_setPivotY }, - { "nSetCameraDistance", "(JF)V", (void*) android_view_DisplayList_setCameraDistance }, - { "nSetLeft", "(JI)V", (void*) android_view_DisplayList_setLeft }, - { "nSetTop", "(JI)V", (void*) android_view_DisplayList_setTop }, - { "nSetRight", "(JI)V", (void*) android_view_DisplayList_setRight }, - { "nSetBottom", "(JI)V", (void*) android_view_DisplayList_setBottom }, - { "nSetLeftTopRightBottom","(JIIII)V", (void*) android_view_DisplayList_setLeftTopRightBottom }, - { "nOffsetLeftAndRight", "(JF)V", (void*) android_view_DisplayList_offsetLeftAndRight }, - { "nOffsetTopAndBottom", "(JF)V", (void*) android_view_DisplayList_offsetTopAndBottom }, - - { "nHasOverlappingRendering", "(J)Z", (void*) android_view_DisplayList_hasOverlappingRendering }, - { "nGetAlpha", "(J)F", (void*) android_view_DisplayList_getAlpha }, - { "nGetLeft", "(J)F", (void*) android_view_DisplayList_getLeft }, - { "nGetTop", "(J)F", (void*) android_view_DisplayList_getTop }, - { "nGetRight", "(J)F", (void*) android_view_DisplayList_getRight }, - { "nGetBottom", "(J)F", (void*) android_view_DisplayList_getBottom }, - { "nGetCameraDistance", "(J)F", (void*) android_view_DisplayList_getCameraDistance }, - { "nGetScaleX", "(J)F", (void*) android_view_DisplayList_getScaleX }, - { "nGetScaleY", "(J)F", (void*) android_view_DisplayList_getScaleY }, - { "nGetTranslationX", "(J)F", (void*) android_view_DisplayList_getTranslationX }, - { "nGetTranslationY", "(J)F", (void*) android_view_DisplayList_getTranslationY }, - { "nGetRotation", "(J)F", (void*) android_view_DisplayList_getRotation }, - { "nGetRotationX", "(J)F", (void*) android_view_DisplayList_getRotationX }, - { "nGetRotationY", "(J)F", (void*) android_view_DisplayList_getRotationY }, - { "nGetPivotX", "(J)F", (void*) android_view_DisplayList_getPivotX }, - { "nGetPivotY", "(J)F", (void*) android_view_DisplayList_getPivotY }, -#endif -}; - -#ifdef USE_OPENGL_RENDERER - #define FIND_CLASS(var, className) \ - var = env->FindClass(className); \ - LOG_FATAL_IF(! var, "Unable to find class " className); - - #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ - var = env->GetMethodID(clazz, methodName, methodDescriptor); \ - LOG_FATAL_IF(! var, "Unable to find method " methodName); -#else - #define FIND_CLASS(var, className) - #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) -#endif - -int register_android_view_DisplayList(JNIEnv* env) { - return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); -} - -}; - diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index a4e6679..aa6a035 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -879,7 +879,7 @@ static jint android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, jobject clazz, jlong rendererPtr, jlong displayListPtr, jobject dirty, jint flags) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); android::uirenderer::Rect bounds; status_t status = renderer->drawDisplayList(displayList, bounds, flags); if (status != DrawGlInfo::kStatusDone && dirty != NULL) { @@ -975,7 +975,7 @@ static void android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) { #ifdef USE_OPENGL_RENDERER int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor); - android::uirenderer::DisplayList::outputLogBuffer(fd); + android::uirenderer::RenderNode::outputLogBuffer(fd); #endif // USE_OPENGL_RENDERER } diff --git a/core/jni/android_view_GLRenderer.cpp b/core/jni/android_view_GLRenderer.cpp index b7e795e..228a92e 100644 --- a/core/jni/android_view_GLRenderer.cpp +++ b/core/jni/android_view_GLRenderer.cpp @@ -143,7 +143,7 @@ static void android_view_GLRenderer_destroyLayer(JNIEnv* env, jobject clazz, static void android_view_GLRenderer_setDisplayListData(JNIEnv* env, jobject clazz, jlong displayListPtr, jlong newDataPtr) { using namespace android::uirenderer; - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); displayList->setData(newData); } diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp index 5b21e94..ad2e9ff 100644 --- a/core/jni/android_view_HardwareLayer.cpp +++ b/core/jni/android_view_HardwareLayer.cpp @@ -120,7 +120,7 @@ static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject cl jlong layerUpdaterPtr, jlong displayListPtr, jint left, jint top, jint right, jint bottom) { DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); layer->setDisplayList(displayList, left, top, right, bottom); } diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp new file mode 100644 index 0000000..2f69b8b --- /dev/null +++ b/core/jni/android_view_RenderNode.cpp @@ -0,0 +1,464 @@ +/* + * 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. + */ + +#define LOG_TAG "OpenGLRenderer" + +#include <EGL/egl.h> + +#include "jni.h" +#include "GraphicsJNI.h" +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> + +#include <DisplayList.h> +#include <DisplayListRenderer.h> + +namespace android { + +using namespace uirenderer; + +/** + * Note: OpenGLRenderer JNI layer is generated and compiled only on supported + * devices. This means all the logic must be compiled only when the + * preprocessor variable USE_OPENGL_RENDERER is defined. + */ +#ifdef USE_OPENGL_RENDERER + +// ---------------------------------------------------------------------------- +// DisplayList view properties +// ---------------------------------------------------------------------------- + +static void android_view_RenderNode_setDisplayListName(JNIEnv* env, + jobject clazz, jlong displayListPtr, jstring name) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + if (name != NULL) { + const char* textArray = env->GetStringUTFChars(name, NULL); + displayList->setName(textArray); + env->ReleaseStringUTFChars(name, textArray); + } +} + +static void android_view_RenderNode_output(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->output(); +} + +static jlong android_view_RenderNode_create(JNIEnv* env, jobject clazz) { + RenderNode* displayList = new RenderNode(); + return reinterpret_cast<jlong>(displayList); +} + +static void android_view_RenderNode_destroyDisplayList(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + RenderNode::destroyDisplayListDeferred(displayList); +} + +// ---------------------------------------------------------------------------- +// DisplayList view properties +// ---------------------------------------------------------------------------- + +static void android_view_RenderNode_setCaching(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean caching) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setCaching(caching); +} + +static void android_view_RenderNode_setStaticMatrix(JNIEnv* env, + jobject clazz, jlong displayListPtr, jlong matrixPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); + displayList->properties().setStaticMatrix(matrix); +} + +static void android_view_RenderNode_setAnimationMatrix(JNIEnv* env, + jobject clazz, jlong displayListPtr, jlong matrixPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr); + displayList->properties().setAnimationMatrix(matrix); +} + +static void android_view_RenderNode_setClipToBounds(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean clipToBounds) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setClipToBounds(clipToBounds); +} + +static void android_view_RenderNode_setIsolatedZVolume(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean shouldIsolate) { + // No-op, TODO: Remove Java usage of this method +} + +static void android_view_RenderNode_setProjectBackwards(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean shouldProject) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setProjectBackwards(shouldProject); +} + +static void android_view_RenderNode_setProjectionReceiver(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean shouldRecieve) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setProjectionReceiver(shouldRecieve); +} + +static void android_view_RenderNode_setOutline(JNIEnv* env, + jobject clazz, jlong displayListPtr, jlong outlinePathPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + SkPath* outline = reinterpret_cast<SkPath*>(outlinePathPtr); + displayList->properties().setOutline(outline); +} + +static void android_view_RenderNode_setClipToOutline(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean clipToOutline) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setClipToOutline(clipToOutline); +} + +static void android_view_RenderNode_setCastsShadow(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean castsShadow) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setCastsShadow(castsShadow); +} + +static void android_view_RenderNode_setUsesGlobalCamera(JNIEnv* env, + jobject clazz, jlong displayListPtr, jboolean usesGlobalCamera) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setUsesGlobalCamera(usesGlobalCamera); +} + +static void android_view_RenderNode_setAlpha(JNIEnv* env, + jobject clazz, jlong displayListPtr, float alpha) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setAlpha(alpha); +} + +static void android_view_RenderNode_setHasOverlappingRendering(JNIEnv* env, + jobject clazz, jlong displayListPtr, bool hasOverlappingRendering) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setHasOverlappingRendering(hasOverlappingRendering); +} + +static void android_view_RenderNode_setTranslationX(JNIEnv* env, + jobject clazz, jlong displayListPtr, float tx) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setTranslationX(tx); +} + +static void android_view_RenderNode_setTranslationY(JNIEnv* env, + jobject clazz, jlong displayListPtr, float ty) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setTranslationY(ty); +} + +static void android_view_RenderNode_setTranslationZ(JNIEnv* env, + jobject clazz, jlong displayListPtr, float tz) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setTranslationZ(tz); +} + +static void android_view_RenderNode_setRotation(JNIEnv* env, + jobject clazz, jlong displayListPtr, float rotation) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setRotation(rotation); +} + +static void android_view_RenderNode_setRotationX(JNIEnv* env, + jobject clazz, jlong displayListPtr, float rx) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setRotationX(rx); +} + +static void android_view_RenderNode_setRotationY(JNIEnv* env, + jobject clazz, jlong displayListPtr, float ry) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setRotationY(ry); +} + +static void android_view_RenderNode_setScaleX(JNIEnv* env, + jobject clazz, jlong displayListPtr, float sx) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setScaleX(sx); +} + +static void android_view_RenderNode_setScaleY(JNIEnv* env, + jobject clazz, jlong displayListPtr, float sy) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setScaleY(sy); +} + +static void android_view_RenderNode_setTransformationInfo(JNIEnv* env, + jobject clazz, jlong displayListPtr, float alpha, + float translationX, float translationY, float translationZ, + float rotation, float rotationX, float rotationY, float scaleX, float scaleY) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setAlpha(alpha); + displayList->properties().setTranslationX(translationX); + displayList->properties().setTranslationY(translationY); + displayList->properties().setTranslationZ(translationZ); + displayList->properties().setRotation(rotation); + displayList->properties().setRotationX(rotationX); + displayList->properties().setRotationY(rotationY); + displayList->properties().setScaleX(scaleX); + displayList->properties().setScaleY(scaleY); +} + +static void android_view_RenderNode_setPivotX(JNIEnv* env, + jobject clazz, jlong displayListPtr, float px) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setPivotX(px); +} + +static void android_view_RenderNode_setPivotY(JNIEnv* env, + jobject clazz, jlong displayListPtr, float py) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setPivotY(py); +} + +static void android_view_RenderNode_setCameraDistance(JNIEnv* env, + jobject clazz, jlong displayListPtr, float distance) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setCameraDistance(distance); +} + +static void android_view_RenderNode_setLeft(JNIEnv* env, + jobject clazz, jlong displayListPtr, int left) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setLeft(left); +} + +static void android_view_RenderNode_setTop(JNIEnv* env, + jobject clazz, jlong displayListPtr, int top) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setTop(top); +} + +static void android_view_RenderNode_setRight(JNIEnv* env, + jobject clazz, jlong displayListPtr, int right) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setRight(right); +} + +static void android_view_RenderNode_setBottom(JNIEnv* env, + jobject clazz, jlong displayListPtr, int bottom) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setBottom(bottom); +} + +static void android_view_RenderNode_setLeftTopRightBottom(JNIEnv* env, + jobject clazz, jlong displayListPtr, int left, int top, + int right, int bottom) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().setLeftTopRightBottom(left, top, right, bottom); +} + +static void android_view_RenderNode_offsetLeftAndRight(JNIEnv* env, + jobject clazz, jlong displayListPtr, float offset) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().offsetLeftRight(offset); +} + +static void android_view_RenderNode_offsetTopAndBottom(JNIEnv* env, + jobject clazz, jlong displayListPtr, float offset) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + displayList->properties().offsetTopBottom(offset); +} + +static jboolean android_view_RenderNode_hasOverlappingRendering(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().hasOverlappingRendering(); +} + +static jfloat android_view_RenderNode_getAlpha(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getAlpha(); +} + +static jfloat android_view_RenderNode_getLeft(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getLeft(); +} + +static jfloat android_view_RenderNode_getTop(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getTop(); +} + +static jfloat android_view_RenderNode_getRight(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getRight(); +} + +static jfloat android_view_RenderNode_getBottom(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getBottom(); +} + +static jfloat android_view_RenderNode_getCameraDistance(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getCameraDistance(); +} + +static jfloat android_view_RenderNode_getScaleX(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getScaleX(); +} + +static jfloat android_view_RenderNode_getScaleY(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getScaleY(); +} + +static jfloat android_view_RenderNode_getTranslationX(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getTranslationX(); +} + +static jfloat android_view_RenderNode_getTranslationY(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getTranslationY(); +} + +static jfloat android_view_RenderNode_getRotation(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getRotation(); +} + +static jfloat android_view_RenderNode_getRotationX(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getRotationX(); +} + +static jfloat android_view_RenderNode_getRotationY(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getRotationY(); +} + +static jfloat android_view_RenderNode_getPivotX(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getPivotX(); +} + +static jfloat android_view_RenderNode_getPivotY(JNIEnv* env, + jobject clazz, jlong displayListPtr) { + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); + return displayList->properties().getPivotY(); +} + +#endif // USE_OPENGL_RENDERER + +// ---------------------------------------------------------------------------- +// JNI Glue +// ---------------------------------------------------------------------------- + +const char* const kClassPathName = "android/view/RenderNode"; + +static JNINativeMethod gMethods[] = { +#ifdef USE_OPENGL_RENDERER + { "nCreate", "()J", (void*) android_view_RenderNode_create }, + { "nDestroyDisplayList", "(J)V", (void*) android_view_RenderNode_destroyDisplayList }, + { "nSetDisplayListName", "(JLjava/lang/String;)V", + (void*) android_view_RenderNode_setDisplayListName }, + { "nOutput", "(J)V", (void*) android_view_RenderNode_output }, + + { "nSetCaching", "(JZ)V", (void*) android_view_RenderNode_setCaching }, + { "nSetStaticMatrix", "(JJ)V", (void*) android_view_RenderNode_setStaticMatrix }, + { "nSetAnimationMatrix", "(JJ)V", (void*) android_view_RenderNode_setAnimationMatrix }, + { "nSetClipToBounds", "(JZ)V", (void*) android_view_RenderNode_setClipToBounds }, + { "nSetIsolatedZVolume", "(JZ)V", (void*) android_view_RenderNode_setIsolatedZVolume }, + { "nSetProjectBackwards", "(JZ)V", (void*) android_view_RenderNode_setProjectBackwards }, + { "nSetProjectionReceiver","(JZ)V", (void*) android_view_RenderNode_setProjectionReceiver }, + { "nSetOutline", "(JJ)V", (void*) android_view_RenderNode_setOutline }, + { "nSetClipToOutline", "(JZ)V", (void*) android_view_RenderNode_setClipToOutline }, + { "nSetCastsShadow", "(JZ)V", (void*) android_view_RenderNode_setCastsShadow }, + { "nSetUsesGlobalCamera", "(JZ)V", (void*) android_view_RenderNode_setUsesGlobalCamera }, + { "nSetAlpha", "(JF)V", (void*) android_view_RenderNode_setAlpha }, + { "nSetHasOverlappingRendering", "(JZ)V", + (void*) android_view_RenderNode_setHasOverlappingRendering }, + { "nSetTranslationX", "(JF)V", (void*) android_view_RenderNode_setTranslationX }, + { "nSetTranslationY", "(JF)V", (void*) android_view_RenderNode_setTranslationY }, + { "nSetTranslationZ", "(JF)V", (void*) android_view_RenderNode_setTranslationZ }, + { "nSetRotation", "(JF)V", (void*) android_view_RenderNode_setRotation }, + { "nSetRotationX", "(JF)V", (void*) android_view_RenderNode_setRotationX }, + { "nSetRotationY", "(JF)V", (void*) android_view_RenderNode_setRotationY }, + { "nSetScaleX", "(JF)V", (void*) android_view_RenderNode_setScaleX }, + { "nSetScaleY", "(JF)V", (void*) android_view_RenderNode_setScaleY }, + { "nSetTransformationInfo","(JFFFFFFFFF)V", + (void*) android_view_RenderNode_setTransformationInfo }, + { "nSetPivotX", "(JF)V", (void*) android_view_RenderNode_setPivotX }, + { "nSetPivotY", "(JF)V", (void*) android_view_RenderNode_setPivotY }, + { "nSetCameraDistance", "(JF)V", (void*) android_view_RenderNode_setCameraDistance }, + { "nSetLeft", "(JI)V", (void*) android_view_RenderNode_setLeft }, + { "nSetTop", "(JI)V", (void*) android_view_RenderNode_setTop }, + { "nSetRight", "(JI)V", (void*) android_view_RenderNode_setRight }, + { "nSetBottom", "(JI)V", (void*) android_view_RenderNode_setBottom }, + { "nSetLeftTopRightBottom","(JIIII)V", (void*) android_view_RenderNode_setLeftTopRightBottom }, + { "nOffsetLeftAndRight", "(JF)V", (void*) android_view_RenderNode_offsetLeftAndRight }, + { "nOffsetTopAndBottom", "(JF)V", (void*) android_view_RenderNode_offsetTopAndBottom }, + + { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, + { "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha }, + { "nGetLeft", "(J)F", (void*) android_view_RenderNode_getLeft }, + { "nGetTop", "(J)F", (void*) android_view_RenderNode_getTop }, + { "nGetRight", "(J)F", (void*) android_view_RenderNode_getRight }, + { "nGetBottom", "(J)F", (void*) android_view_RenderNode_getBottom }, + { "nGetCameraDistance", "(J)F", (void*) android_view_RenderNode_getCameraDistance }, + { "nGetScaleX", "(J)F", (void*) android_view_RenderNode_getScaleX }, + { "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY }, + { "nGetTranslationX", "(J)F", (void*) android_view_RenderNode_getTranslationX }, + { "nGetTranslationY", "(J)F", (void*) android_view_RenderNode_getTranslationY }, + { "nGetRotation", "(J)F", (void*) android_view_RenderNode_getRotation }, + { "nGetRotationX", "(J)F", (void*) android_view_RenderNode_getRotationX }, + { "nGetRotationY", "(J)F", (void*) android_view_RenderNode_getRotationY }, + { "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX }, + { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY }, +#endif +}; + +#ifdef USE_OPENGL_RENDERER + #define FIND_CLASS(var, className) \ + var = env->FindClass(className); \ + LOG_FATAL_IF(! var, "Unable to find class " className); + + #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ + var = env->GetMethodID(clazz, methodName, methodDescriptor); \ + LOG_FATAL_IF(! var, "Unable to find method " methodName); +#else + #define FIND_CLASS(var, className) + #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) +#endif + +int register_android_view_RenderNode(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)); +} + +}; + diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 2b20758..28cee4b 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -106,7 +106,7 @@ static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, static void android_view_ThreadedRenderer_setDisplayListData(JNIEnv* env, jobject clazz, jlong proxyPtr, jlong displayListPtr, jlong newDataPtr) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); DisplayListData* newData = reinterpret_cast<DisplayListData*>(newDataPtr); proxy->setDisplayListData(displayList, newData); } @@ -115,7 +115,7 @@ static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject c jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop, jint dirtyRight, jint dirtyBottom) { RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr); - DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr); + RenderNode* displayList = reinterpret_cast<RenderNode*>(displayListPtr); proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b99cb90..c2159fb 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1271,9 +1271,10 @@ <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS} that removes restrictions on where broadcasts can be sent and allows other types of interactions. --> + <!-- TODO: Remove the system protection level.--> <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:permissionGroup="android.permission-group.SYSTEM_TOOLS" - android:protectionLevel="signature" + android:protectionLevel="signature|system" android:label="@string/permlab_interactAcrossUsersFull" android:description="@string/permdesc_interactAcrossUsersFull" /> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 0b9ac7f..5cb5709 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Laat die houer toe om die opstellingsprogram wat deur die diensverskaffer voorsien word, op te roep. Behoort nooit vir gewone programme nodig te wees nie."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"luister vir waarnemings oor netwerktoestande"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Laat \'n program luister vir waarnemings oor netwerktoestande. Behoort nooit nodig te wees vir normale programme nie."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"verander invoertoestelkalibrasie"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Laat die program toe om die kalibrasieparameters van die raakskerm te wysig. Dit behoort nooit vir normale programme nodig te wees nie."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Beheer lengte en watter karakters wat in die skermontsluit-wagwoorde gebruik word."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 5701852..5509121 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ያዢው በድምጸ-ተያያዥ ሞደም የቀረበው የውቅር መተግበሪያውን እንዲጠራው ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አያስፈልግም።"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን ያዳምጣል"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"አንድ መተግበሪያ በአውታረ መረብ ሁኔታዎች ላይ የተስተዋሉ ነገሮችን እንዲያዳምጥ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ አስፈላጊ ሊሆን አይገባም።"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"የግቤት መሣሪያ ማስተካከያ ቀይር"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"መተግበሪያው የማያ ንካ የማስተካከያ ልኬቶቹን እንዲቀይር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"በማያ-መክፈት የተፈቀዱ የይለፍ ቃል ርዝመት እና ቁምፊዎች ተቆጣጠር።"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string> @@ -1123,9 +1125,9 @@ <string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> እያሄደ ነው"</string> <string name="app_running_notification_text" msgid="4653586947747330058">"ተጨማሪ መረጃ ለማግኘት ወይም መተግበሪያውን ለማቆም ይንኩ።"</string> <string name="ok" msgid="5970060430562524910">"እሺ"</string> - <string name="cancel" msgid="6442560571259935130">"ሰርዝ"</string> + <string name="cancel" msgid="6442560571259935130">"ይቅር"</string> <string name="yes" msgid="5362982303337969312">"እሺ"</string> - <string name="no" msgid="5141531044935541497">"ሰርዝ"</string> + <string name="no" msgid="5141531044935541497">"ይቅር"</string> <string name="dialog_alert_title" msgid="2049658708609043103">"ትኩረት"</string> <string name="loading" msgid="7933681260296021180">"በመጫን ላይ…"</string> <string name="capital_on" msgid="1544682755514494298">"በ"</string> @@ -1227,7 +1229,7 @@ <string name="sms_short_code_details" msgid="3492025719868078457">"ይሄ በተንቀሳቃሽ ስልክ መለያዎ ላይ "<font fgcolor="#ffffb060">"ክፍያዎችን ሊያስከትል ይችላል"</font>"።"</string> <string name="sms_premium_short_code_details" msgid="5523826349105123687"><font fgcolor="#ffffb060">"ይሄ በተንቀሳቃሽ ስልክ መለያዎ ላይ ክፍያዎችን ያስከትላል።"</font></string> <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ላክ"</string> - <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ሰርዝ"</string> + <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"ይቅር"</string> <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"ምርጫዬን አስታውስ"</string> <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"ይሄንን በኋላ ላይ በቅንብሮች > መተግበሪያዎች ውስጥ ሊቀይሩት ይችላሉ"</string> <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"ሁልጊዜ ፍቀድ"</string> @@ -1425,7 +1427,7 @@ <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string> <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string> <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string> - <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ተወው"</string> + <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string> <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string> <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ተከናውኗል"</string> <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ሞድ ለውጥ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 798ea7a..d17b1d1 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"للسماح للمالك باستدعاء تطبيق التهيئة الذي يوفره مشغل شبكة الجوال. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"الاستماع إلى ملاحظات حول أحوال الشبكة"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"للسماح للتطبيق بالاستماع إلى ملاحظات حول أحوال الشبكة. لا حاجة إلى هذا مع التطبيقات العادية."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"تغيير معايرة أجهزة الإدخال"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"يتيح للتطبيق إمكانية تعديل معلمات المعايرة في شاشة اللمس. يجب عدم اللجوء إليه مع التطبيقات العادية."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"يمكنك التحكم في الطول والأحرف المسموح بها في كلمات مرور إلغاء تأمين الشاشة."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index f76ad7f..691aff26 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Разрешава на притежателя да извиква предоставеното от оператора приложение за конфигуриране. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"слушане за наблюдения на мрежовите условия"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Разрешава на приложението да слуша за наблюдения на мрежовите условия. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"промяна на калибрирането на устройството за въвеждане"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Разрешава на приложението да променя параметрите на калибриране на сензорния екран. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролирайте дължината и разрешените знаци за паролите за отключване на екрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index dc8128a..682e0ea 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet que el titular invoqui l\'aplicació de configuració proporcionada per l\'operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"conèixer les observacions sobre les condicions de la xarxa"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet que una aplicació conegui les observacions sobre les condicions de la xarxa. No s\'ha de necessitar mai per a aplicacions normals."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"canviar el calibratge del dispositiu d\'entrada"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet que l\'aplicació modifiqui els paràmetres de calibratge de la pantalla tàctil. S\'ha de procurar no fer servir mai aquesta opció per a les aplicacions normals."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controla la longitud i els caràcters permesos a les contrasenyes de desbloqueig de pantalla."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar intents de desbloqueig de pantalla"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 9745cdc..37e228c 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje vyvolání konfigurační aplikace poskytnuté operátorem. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"naslouchat informacím o stavu sítě"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikaci naslouchat informacím o stavu sítě. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"měnit kalibraci vstupního zařízení"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Umožňuje aplikaci měnit parametry kalibrace dotykové obrazovky. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Řídit délku hesel pro odemčení obrazovky a povolené znaky."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index ca12213..5acf558 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Tillader, at brugeren aktiverer konfigurationsappen, der er forsynet af mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"observer netværksforhold"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillader, at en applikation observerer netværksforhold. Bør aldrig være nødvendigt for almindelige apps."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"skift kalibrering for inputenheden"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Tillader, at appen ændrer kalibreringsparametrene for berøringsskærmen. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller længden samt tilladte tegn i adgangskoder til oplåsning af skærmen."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 404d4cc..f87865d 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ermöglicht dem Inhaber, die vom Mobilfunkanbieter bereitgestellte Konfigurations-App aufzurufen. Sollte für normale Apps nie benötigt werden."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Informationen zu den Netzwerkbedingungen erfassen"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ermöglicht der App, Informationen zu den Netzwerkbedingungen zu erfassen. Sollte für normale Apps nie benötigt werden."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Kalibrierung für Eingabegerät ändern"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ermöglicht der App, die Kalibrierungsparameter des Touchscreens zu ändern. Für normale Apps sollte dies nie erforderlich sein."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Bildschirms festlegen"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 1c3e185..ffe2501 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Επιτρέπει στον κάτοχο την κλήση της εφαρμογής διαμόρφωσης που παρέχεται από την εταιρεία κινητής τηλεφωνίας. Δεν απαιτείται για κανονικές εφαρμογές."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"λήψη παρατηρήσεων σχετικά με την κατάσταση δικτύου"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Επιτρέπει σε μια εφαρμογή να λαμβάνει παρατηρήσεις σχετικά με την κατάσταση δικτύου. Δεν θα πρέπει να απαιτείται ποτέ για κανονικές εφαρμογές."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"αλλαγή βαθμονόμησης της συσκευής εισόδου"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Επιτρέπει στην εφαρμογή να τροποποιεί τις παραμέτρους βαθμονόμησης της οθόνης αφής. Δεν απαιτείται για τις κανονικές εφαρμογές."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Έλεγχος του μεγέθους και των χαρακτήρων που επιτρέπονται στους κωδικούς πρόσβασης ξεκλειδώματος οθόνης."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index c4b3a2b..19ea67b 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"change input device calibration"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index c4b3a2b..19ea67b 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"listen for observations on network conditions"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Allows an application to listen for observations on network conditions. Should never be needed for normal apps."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"change input device calibration"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Control the length and the characters allowed in screen-unlock passwords."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 1446aff..ec4ed33 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite al propietario ejecutar la aplicación de configuración proporcionada por el proveedor. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Detectar cambios en el estado de la red"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. Las aplicaciones normales no deberían necesitar este permiso."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Cambiar la calibración del dispositivo de entrada"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que la aplicación modifique los parámetros de calibración de la pantalla táctil. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas para desbloquear la pantalla"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 6d4ee8e..cb68b67 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite ejecutar la aplicación de configuración proporcionada por el operador. No debe ser necesario para aplicaciones normales."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar cambios en el estado de la red"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que una aplicación detecte cambios en el estado de la red. No debe ser necesario para aplicaciones normales."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"cambiar la calibración del dispositivo de entrada"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que la aplicación modifique los parámetros de calibración de la pantalla táctil. No debe ser necesario para las aplicaciones normales."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar la longitud y los caracteres permitidos en las contraseñas de bloqueo de pantalla"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index 629852f..039fa9c 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lubab omanikul aktiveerida operaatoripoolse konfiguratsioonirakenduse. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"võrgutingimuste teabe kuulamine"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lubab rakendusel kuulata võrgutingimuste teavet. Ei ole kunagi vajalik tavaliste rakenduste puhul."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"sisendseadme kalibreerimise muutmine"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lubab rakendusel muuta puuteekraani kalibreerimisparameetreid. Ei tohiks kunagi olla vajalik tavaliste rakenduste puhul."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrollige ekraaniluku avamise paroolide pikkust ja tähemärke."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index a73d136..857a1ea 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -256,7 +256,7 @@ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"حذف نصب میانبرها"</string> <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"به برنامه اجازه میدهد میانبرهای صفحه اصلی را بدون دخالت کاربر حذف کند."</string> <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ترسیم مجدد مسیر تماسهای خروجی"</string> - <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"به برنامه اجازه میدهد عددی را که در طی یک تماس خروجی شمارهگیری شده ببیند و این اختیار را دارد که تماس را به شماره دیگری هدایت کند یا کلاً تماس را قطع کند."</string> + <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"به برنامه اجازه میدهد عددی را که در طی یک تماس خروجی شمارهگیری شده، ببیند و این اختیار را دارد که تماس را به شماره دیگری هدایت کند یا کلاً تماس را قطع کند."</string> <string name="permlab_receiveSms" msgid="8673471768947895082">"دریافت پیامهای نوشتاری (پیامک)"</string> <string name="permdesc_receiveSms" msgid="6424387754228766939">"به برنامه اجازه میدهد پیامکها را دریافت و پردازش کند. این یعنی برنامه میتواند پیامهای ارسالی به دستگاه شما را بدون نمایش آنها به شما حذف یا کنترل کند."</string> <string name="permlab_receiveMms" msgid="1821317344668257098">"دریافت پیامهای نوشتاری (MMS)"</string> @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"به دارنده اجازه میدهد که تنظیمات برنامه شرکت مخابراتی را لغو کند. هرگز برای برنامههای معمولی مورد نیاز نیست."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"گوش دادن برای بررسی شرایط شبکه"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"به برنامه امکان میدهد برای بررسی شرایط شبکه گوش دهد. این امکان هرگز نباید برای برنامههای معمولی مورد نیاز باشد."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"تغییر کالیبراسیون دستگاه ورودی"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"به برنامه امکان میدهد پارامترهای صفحه لمسی را کالیبره کند. هرگز نباید برای برنامههای عادی مورد نیاز باشد."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"طول و نویسههای مجاز در گذرواژههای بازکردن قفل صفحه را کنترل کنید."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاشهای قفل گشایی صفحه"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 4e9ddd1..fe3c461 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Antaa luvanhaltijan käynnistää palveluntarjoajan määrityssovelluksen. Ei tavallisten sovelluksien käyttöön."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"verkon tilahavaintojen kuunteleminen"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Antaa sovellukselle luvan kuunnella verkon tilahavaintoja. Ei tavallisten sovellusten käyttöön."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"Muuttaa syöttölaitteen kalibrointia."</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Antaa sovelluksen muokata kosketusnäytön kalibrointiparametreja. Ei tavallisten sovellusten käyttöön."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Hallinnoi ruudun lukituksenpoistosalasanoissa sallittuja merkkejä ja salasanan pituutta."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 79a1ab1..acf58ca 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par le fournisseur de services. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter les observations sur les conditions du réseau. Ne devrait jamais être nécessaire pour les applications standards."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifier le calibrage du périphérique d\'entrée"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permet à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index f869af5..bcba168 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permet à l\'application autorisée de faire appel à l\'application de configuration fournie par l\'opérateur. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"détecter des observations sur les conditions du réseau"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permet à une application de détecter des observations sur les conditions du réseau. Les applications standards ne devraient pas nécessiter cette autorisation."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifier le calibrage du périphérique d\'entrée"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permettre à l\'application de modifier les paramètres de calibrage de l\'écran tactile. Ne devrait jamais être nécessaire pour les applications standards."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Choisir le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 00fdd7c..05e5941 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"धारक को वाहक के द्वारा उपलब्ध कराया गया कॉन्फ़िगरेशन ऐप्स प्रारंभ करने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"नेटवर्क स्थितियों के अवलोकनों को सुनें"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ऐप्स को नेटवर्क स्थितियों के अवलोकनों को सुनने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट उपकरण कैलिब्रेशन बदलें"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ऐप्स को टच स्क्रीन के कैलिब्रेशन पैरामीटर को बदलने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"स्क्रीन-अनलॉक पासवर्ड में अनुमति प्राप्त लंबाई और वर्णों को नियंत्रित करें."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 6224106..19afc6c 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -657,7 +657,7 @@ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"čitanje sadržaja SD kartice"</string> <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Aplikaciji omogućuje čitanje sadržaja vaše USB pohrane."</string> <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Aplikaciji omogućuje čitanje sadržaja vaše SD kartice."</string> - <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmjena/brisanje sadrž. USB-a"</string> + <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"izmjena/brisanje sadržaja USB-a"</string> <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"izmjena ili brisanje sadržaja SD kartice"</string> <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Dopušta pisanje u USB pohranu."</string> <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Aplikaciji omogućuje pisanje na SD karticu."</string> @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Dopušta nositelju pozivanje operaterove aplikacije za konfiguraciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"praćenje motrenja mrežnih uvjeta"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Omogućuje aplikaciji praćenje motrenja mrežnih uvjeta. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"promjena kalibracije uređaja za unos"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Omogućuje aplikaciji izmjenu parametara kalibracije dodirnog zaslona. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Upravljajte duljinom zaporki za otključavanje zaslona i dopuštenim znakovima u tim zaporkama."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index c0f9c27..1d6b16d 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lehetővé teszi a használó számára a szolgáltató által biztosított konfigurációs alkalmazás hívását. A normál alkalmazásoknak erre soha nincs szükségük."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"hálózati körülményekkel kapcsolatos észrevételek figyelemmel kísérése"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Lehetővé teszi egy alkalmazás számára, hogy figyelemmel kísérje a hálózati körülményekkel kapcsolatos észrevételeket. A normál alkalmazásoknak erre soha nincs szükségük."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"beviteli eszköz kalibrációjának módosítása"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lehetővé teszi, hogy alkalmazás módosítsa az érintőképernyő kalibrációs paramétereit. A normál alkalmazásoknál erre elvileg soha nincs szükség."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"A képernyőzár-feloldási jelszavakban engedélyezett karakterek és hosszúság vezérlése."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 8a0f901..62464ba 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Թույլ է տալիս սեփականատիրոջը գործարկել օպերատորի կողմից տրամադրված կազմաձևման ծրագիրը: Սովորական ծրագրերի համար երբևէ չպետք է անհրաժեշտ լինի:"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"լսել դիտարկումներ ցանցային պայմանների վերաբերյալ"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Հավելվածին թույլ է տալիս լսել դիտարկումներ ցանցային պայմանների վերաբերյալ: Սովորական հավելվածների համար երբեք պետք չի գալիս:"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"փոփոխել մուտքի սարքի չափաբերումը"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Թույլ է տալիս ծրագրին փոփոխել հպէկրանի չափաբերման կարգավորումները: Սովորական ծրագրերի համար երբեք պետք չի գալու:"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Վերահսկել էկրանի ապակողպման գաղտնաբառերի թույլատրելի երկարությունն ու գրանշանները:"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 07e6cb2..b3b0d2b 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Memungkinkan pemegang meminta aplikasi konfigurasi yang disediakan operator. Tidak pernah diperlukan aplikasi normal."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"mendengar untuk observasi kondisi jaringan"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Memungkinkan aplikasi mendengar untuk observasi kondisi jaringan. Tidak pernah dibutuhkan oleh aplikasi normal."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"mengubah kalibrasi perangkat masukan"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Memungkinkan aplikasi mengubah parameter kalibrasi layar sentuh. Tidak diperlukan oleh aplikasi normal."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrol panjang dan karakter yang diizinkan dalam sandi pembuka layar."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 0f59bba..3faca1a 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascolto delle osservazioni sulle condizioni di rete"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Consente a un\'applicazione di ascoltare le osservazioni sulle condizioni di rete. Da non utilizzare mai con app normali."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"modifica calibrazione del dispositivo di immissione"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Consente all\'app di modificare i parametri di calibrazione del touch screen. Questa opzione non deve essere utilizzata per le app normali."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Impostazione regole password"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlla la lunghezza e i caratteri ammessi nelle password di sblocco dello schermo."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Controllo tentativi di sblocco dello schermo"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 128fbc7..c8f0dd5 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ההרשאה הזו מאפשרת לבעלים להפעיל את אפליקציית התצורה שסופקה על ידי ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"קליטת מעקב אחר תנאי רשת"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"מאפשרת לאפליקציה לקלוט מעקב אחר תנאי רשת. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"שינוי הכיול של מכשיר קלט"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"מאפשרת לאפליקציה לשנות את פרמטרי הכיול של מסך המגע. לעולם לא אמורה להיות נחוצה לאפליקציות רגילות."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"שלוט באורך ובתווים המותרים בסיסמאות לביטול נעילת מסך."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 7892d69..4a26208 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"携帯通信会社が提供する設定アプリを呼び出すことを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ネットワーク状況監視のためのリッスン"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ネットワーク状況を監視するためリッスンすることをアプリに許可します。通常のアプリで必要になることはありません。"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"入力デバイスの調整を変更"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"タッチスクリーンの調整パラメータの変更をアプリに許可します。通常のアプリでは必要ありません。"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"画面ロック解除パスワードの長さと使用できる文字を制御します。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index a48ac95..5dbb83f 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"საშუალებას აძლევს მფლობელს გამოიწვიოს ოპერატორის მიერ მოწოდებული კონფიგურაციის აპი. ჩვეულებრივ აპს ეს წესით არასოდეს არ უნდა დაჭირდეს."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"განხორციელდეს ქსელის მდგომარეობის მონიტორინგი"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"საშუალებას აძლევს აპლიკაციებს განახორციელოს ქსელის მდგომარეობის მონიტორინგი. ეს ფუნქცია ჩვეულებრივ აპებს არ ჭირდება."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"შეყვანის მოწყობილობის კალიბრაციის ცვლილება"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"საშუალებას აძლევს აპს შეცვალოს სენსორული ეკრანის კალიბრაციის პარამეტრები. ჩვეულებრივ აპებს წესით არ უნდა დაჭირდეს."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"გააკონტროლეთ ეკრანის განბლოკვის პაროლში დაშვებული სიმბოლოები და მისი სიგრძე."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 488a439..21a7746 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"អនុញ្ញាតឲ្យម្ចាស់ដកហូតកម្មវិធីកំណត់រចនាសម្ព័ន្ធដែលបានផ្ដល់ដោយក្រុមហ៊ុនបញ្ជូន។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"សង្កេតមើលលើលក្ខខណ្ឌបណ្ដាញ"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ឲ្យកម្មវិធីសង្កេតមើលលើលក្ខខណ្ឌបណ្ដាញ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ប្ដូរចំណុចឧបករណ៍បញ្ចូល"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ឲ្យកម្មវិធីកែប៉ារ៉ាម៉ែត្រកែចំណុចនៃការប៉ះអេក្រង់។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"កំណត់ក្បួនពាក្យសម្ងាត់"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"ពិនិត្យប្រវែង និងតួអក្សរដែលបានអនុញ្ញាតក្នុងពាក្យសម្ងាត់ចាក់សោអេក្រង់។"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"ពិនិត្យការព្យាយាមដោះសោអេក្រង់"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 681aabf..9e46527 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"권한을 가진 프로그램이 이동통신사에서 제공한 구성 앱을 호출하도록 합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"네트워크 상태에 대한 관측 보고 수신"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"애플리케이션이 네트워크 상태에 대한 관측 보고를 수신하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"입력 기기 보정 변경"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"앱이 터치 스크린의 보정 매개변수를 수정할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"화면 잠금해제 비밀번호에 허용되는 길이 및 문자 수를 제어합니다."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index 64dcbc6..56a05c3 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງຮ້ອງຂໍແອັບຯປັບຄ່າທີ່ສະໜອງໂດຍຜູ່ໃຫ້ບໍລິການ. ບໍ່ໜ້າຈະຕ້ອງການສຳລັບແອັບຯທົ່ວໄປ."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັ່ນຕິດຕາມເພື່ອສັງເກດສະພາບຂອງເຄືອຂ່າຍ. ປົກກະຕິແລ້ວແອັບຯທຳມະດາຈະບໍ່ຕ້ອງການໃຊ້."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ປ່ຽນການວັດແທ້ອຸປະກອນປ້ອນຂໍ້ມູນ"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"ອະນຸຍາດໃຫ້ແອັບຯແກ້ໄຂຄ່າການວັດແທ້ໜ້າຈໍສຳຜັດ. ແອັບຯທຳມະດາບໍ່ຄວນໃຊ້."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"ຄວບຄຸມຄວາມຍາວຂອງໂຕອັກສອນທີ່ສາມາດໃຊ້ກັບລະຫັດປົດລັອກໜ້າຈໍ"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index b379738..22fc1c4 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Turėtojui leidžiama iškviesti operatoriaus pateiktą konfigūravimo programą. Įprastoms programoms to neturėtų prireikti."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"vykdyti tinklo sąlygų stebėjimą"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Leidžiama programai vykdyti tinklo sąlygų stebėjimą. To niekada neturėtų prireikti naudojant įprastas programas."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"keisti įvesties įrenginio kalibravimą"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Leidžiama programai keisti jutiklinio ekrano kalibravimo parametrus. Neturėti prireikti naudojant įprastas programas."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Valdyti leidžiamą ekrano atrakinimo slaptažodžių ilgį ir leidžiamus naudoti simbolius."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 278b0d7..4a207d9 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ļauj īpašniekam izsaukt operatora nodrošināto konfigurācijas lietotni. Parastām lietotnēm tas nekad nav nepieciešams."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"iegūt informāciju par tīkla stāvokļa novērojumiem"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ļauj lietojumprogrammai iegūt informāciju par tīkla stāvokļa novērojumiem. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"mainīt ievadierīces kalibrēšanu"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ļauj lietotnei pārveidot skārienekrāna kalibrēšanas parametrus. Parastām lietotnēm šī atļauja nekad nav nepieciešama."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolē ekrāna atbloķēšanas parolē atļautās rakstzīmes un garumu."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index 3d0b3cb..5e60ce3 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Эзэмшигчид үүрэн компанийн нийлүүлсэн тохируулах апп-г өдөөх боломж олгоно. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Сүлжээний байдлын талаар ажиглалтуудыг хүлээн авах"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Аппликешнд сүлжээний байдлын талаар ажиглалтуудыг хүлээн авахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"оролтын төхөөрөмжийн калибрешныг өөрчлөх"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Мэдрэгчтэй дэлгэцний калибрешн параметрийг өөрчлөхийг апп-д зөвшөөрнө. Энгийн апп-д шаардлагагүй."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Дэлгэц түгжих нууц үгэнд зөвшөөрөгдсөн тэмдэгт болон уртыг удирдах"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index 37d0d0f..c1b7cdb 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Membenarkan pemegang menggunakan apl konfigurasi yang diberikan oleh pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"dengar pemerhatian mengenai keadaan rangkaian"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Membenarkan aplikasi mendengar pemerhatian tentang keadaan rangkaian. Tidak sekali-kali diperlukan untuk apl biasa."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"tukar penentukuran peranti input"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Membenarkan apl mengubah suai parameter penentukuran skrin sentuh. Ini tidak sekali-kali diperlukan untuk apl biasa."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan buka kunci skrin."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 78df5e8..c1cd604 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Gir innehaveren tillatelse til å kalle opp den konfigurasjonsappen som ble levert av operatøren. Dette skal ikke være nødvendig for vanlige apper."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lytte etter observasjoner om nettverksforhold"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Gir appen tillatelse til å lytte etter observasjoner om nettverksforhold. Dette skal ikke være nødvendig for vanlige apper."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"endre kalibreringen av inndataenheter"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Lar appen endre kalibrasjonsparametrene for berøringsskjermen. Denne tillatelsen bør aldri være nødvendig for vanlige apper."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontroller tillatt lengde og tillatte tegn i passord for opplåsing av skjerm."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 8eaebf1..673df4e 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Hiermee kan de houder de door de provider geleverde configuratie-app aanroepen. Nooit vereist voor normale apps."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"controleren op waarnemingen met betrekking tot netwerkomstandigheden"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Hiermee kan een app controleren op waarnemingen met betrekking tot netwerkomstandigheden. Nooit vereist voor normale apps."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"kalibratie van invoerapparaat wijzigen"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Hiermee kan de app de kalibratieparameters van het aanraakscherm aanpassen. Nooit vereist voor normale apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 77d5441..e9d701a 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Zezwala na wywoływanie aplikacji konfiguracyjnej udostępnionej przez operatora. Nieprzeznaczone dla zwykłych aplikacji."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"śledź stan sieci"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Pozwala aplikacji śledzić stan sieci. Nieprzeznaczone dla zwykłych aplikacji."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"zmiana kalibracji urządzenia wejściwego"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Zezwala aplikacji na modyfikowanie parametrów kalibracji ekranu dotykowego. Nieprzeznaczone dla zwykłych aplikacji."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolowanie długości haseł odblokowania ekranu i dozwolonych w nich znaków"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index e92961d..cf38b47 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o titular invoque a aplicação de configuração fornecida pela operadora. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ouvir observações sobre as condições da rede"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que uma aplicação ouça observações sobre as condições da rede. Nunca deverá ser necessário para aplicações normais."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"alterar a calibragem de entrada do dispositivo"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite à aplicação modificar os parâmetros de calibragem do ecrã tátil. Esta funcionalidade nunca deverá ser necessária para aplicações normais."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o comprimento e os caracteres permitidos nas palavras-passe de desbloqueio do ecrã."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index b3481b8..d048d51 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite que o proprietário invoque o aplicativo de configuração fornecido pela operadora. Não deve ser necessário para aplicativos comuns."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"detectar observações nas condições da rede"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite que o aplicativo detecte observações nas condições da rede. Não deve ser necessário para aplicativos comuns."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"alterar calibragem do dispositivo de entrada"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite que o aplicativo modifique os parâmetros de calibragem da tela sensível ao toque. Não deve ser necessário para aplicativos normais."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Controlar o tamanho e os caracteres permitidos nas senhas de desbloqueio de tela."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string> diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml index 9c2c793..8d007e4 100644 --- a/core/res/res/values-rm/strings.xml +++ b/core/res/res/values-rm/strings.xml @@ -1170,6 +1170,10 @@ <skip /> <!-- no translation found for permdesc_accessNetworkConditions (6899102075825272211) --> <skip /> + <!-- no translation found for permlab_setInputCalibration (4902620118878467615) --> + <skip /> + <!-- no translation found for permdesc_setInputCalibration (4527511047549456929) --> + <skip /> <!-- no translation found for policylab_limitPassword (4497420728857585791) --> <skip /> <!-- no translation found for policydesc_limitPassword (3252114203919510394) --> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 016cb16..dd9dd9e 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ascultă observații despre starea rețelei"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"schimbați calibrarea dispozitivului de intrare"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Permite aplicației să modifice parametrii de calibrare a ecranului tactil. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Stabiliţi lungimea şi tipul de caractere permise în parolele pentru deblocarea ecranului."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 5c9e697..f518a0c 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Владелец сможет запускать приложение настроек, предоставленное оператором. Это разрешение не используется обычными приложениями."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Использование данных о состоянии сети"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Приложение сможет использовать данные о состоянии сети. Это разрешение обычно используется только специальными приложениями."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"изменение параметров калибровки экрана"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Приложение сможет изменять параметры калибровки сенсорного экрана. Это разрешение обычно используется только специальными приложениями."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролировать длину и символы при вводе паролей для снятия блокировки экрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 039e1eb..f8e9782 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Umožňuje držiteľovi vyvolať aplikáciu pre konfiguráciu poskytnutú operátorom. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"zachytávať informácie o stave siete"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Umožňuje aplikácii zachytávať informácie o stave siete. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"zmeniť kalibráciu vstupného zariadenia"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Umožňuje aplikácii upraviť parametre kalibrácie dotykovej obrazovky. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ovládanie dĺžky hesiel na odomknutie obrazovky a v nich používané znaky."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 6a909d6..cab43f2 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Lastniku omogoča sproženje operaterjeve aplikacije za konfiguracijo. Tega nikoli ni treba uporabiti za navadne aplikacije."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"spremljanje razmer v omrežju"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Aplikaciji omogoča spremljanje razmer v omrežju. Pri navadnih aplikacijah to ne bi smelo biti potrebno."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"sprememba umerjanja vhodne naprave"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Aplikaciji dovoli spreminjanje parametrov za umerjanje zaslona na dotik. Tega ni treba nikoli uporabiti za navadne aplikacije."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih za odklepanje zaslona."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 9a53a2a..7895ded 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозвољава власнику да позива апликацију са конфигурацијом коју одређује оператер. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"праћење података о условима на мрежи"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозвољава апликацији да прати податке о условима на мрежи. Не би никада требало да буде потребно за нормалне апликације."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"промени калибрацију улазног уређаја"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Дозвољава апликацији да модификује параметре калибрације додирног екрана. Не би требало да буде потребно за нормалне апликације."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролишите дужину и знакове дозвољене у лозинкама за откључавање екрана."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 2e2d3f2..c29f0a3 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Innehavaren tillåts att anropa konfigurationsappen från operatören. Ska inte behövas för vanliga appar."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"lyssna efter information om nätverksförhållanden"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Tillåter att appen lyssnar efter information om nätverksförhållanden. Vanliga appar bör aldrig behöva den här behörigheten."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"ändra kalibreringen för inmatningsenheten"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Tillåter att appen ändrar kalibreringsparametrarna för pekskärmen. Detta behövs aldrig för vanliga appar."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Bestäm hur många och vilka tecken som är tillåtna i skärmlåsets lösenord."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 5b15a7f..3e11aa1 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -256,7 +256,7 @@ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ondoa njia za mikato"</string> <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Huruhusu programu kuondoa njia za mkato za Skrini ya kwanza bila mtumiaji kuingilia."</string> <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"panga upya simu zinazotoka"</string> - <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Huruhusu programu kuona nambari inayopigwa wakati simu inapigwa ikiwa na chaguo la kuelekeza simu kwa nambari tofauti au kukata simu kabisa."</string> + <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Huruhusu programu kuona nambari inayopigwa wakati simu inapigwa ikiwa na chaguo la kuelekeza simu kwenye nambari tofauti au kukata simu kabisa."</string> <string name="permlab_receiveSms" msgid="8673471768947895082">"pokea ujumbe wa maandishi wa SMS"</string> <string name="permdesc_receiveSms" msgid="6424387754228766939">"Inaruhusu programu kupokea na kuchakata ujumbe wa SMS. Hii inamaanisha programu hii inaweza kuchunguza na kufuta ujumbe uliotumwa katika kifaa chako bila ya kukuonyesha."</string> <string name="permlab_receiveMms" msgid="1821317344668257098">"pokea ujumbe wa maandishi wa MMS"</string> @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Inaruhusu kishikiliaji kuomba programu ya usakinishaji inayotolewa na mto huduma. Haipaswi kuhitajika kwa programu za kawaida."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"sikiliza matukio katika hali za mtandao"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Huruhusu programu kusikiliza matukio katika hali za mtandao. Haipaswi kuhitajika kamwe kwa programu za kawaida."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"badilisha urekebishaji wa kifaa cha kuingiza data"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Huruhusu programu kubadilisha vigezo vya urekebishaji vya skrini ya kugusa. Havipaswi kuhitajika kamwe kwa programu za kawaida."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Kuweka kanuni za nenosiri"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kudhibiti urefu na herufi zinazoruhusiwa katika manenosiri ya kufungua skrini."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Kuhesabu idadi ya mara ambazo skrini inajaribu kufunguliwa"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index a4c328e..e07bd7d 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -256,7 +256,7 @@ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ถอนการติดตั้งทางลัด"</string> <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"อนุญาตให้แอปพลิเคชันลบทางลัดหน้าจอหลักโดยไม่ต้องให้ผู้ใช้จัดการ"</string> <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"จัดเส้นทางการโทรออกใหม่"</string> - <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"อนุญาตให้แอปดูหมายเลขที่โทรในระหว่างการโทรออกโดยสามารถเลือกเปลี่ยนเส้นทางการโทรไปยังหมายเลขอื่นหรือยกเลิกการโทรไปเลย"</string> + <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"อนุญาตให้แอปดูหมายเลขที่โทรในระหว่างการโทรออกโดยสามารถเลือกเปลี่ยนเส้นทางการโทรไปยังหมายเลขอื่นหรือยกเลิกการโทรไปเลยได้"</string> <string name="permlab_receiveSms" msgid="8673471768947895082">"รับข้อความ (SMS)"</string> <string name="permdesc_receiveSms" msgid="6424387754228766939">"อนุญาตให้แอปพลิเคชันรับและประมวลผลข้อความ SMS ซึ่งหมายความว่าแอปพลิเคชันจะสามารถตรวจสอบหรือลบข้อความที่ส่งมายังอุปกรณ์ของคุณได้โดยไม่ต้องแสดงให้คุณเห็น"</string> <string name="permlab_receiveMms" msgid="1821317344668257098">"รับข้อความ (MMS)"</string> @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"อนุญาตให้ผู้ใช้สามารถเรียกใช้แอปการกำหนดค่าของผู้ให้บริการ ซึ่งแอปทั่วไปไม่จำเป็นต้องใช้"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"อนุญาตให้แอปพลิเคชันฟังข้อสังเกตเกี่ยวกับสภาวะของเครือข่าย ไม่จำเป็นสำหรับแอปปกติ"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"เปลี่ยนการเทียบมาตรฐานอุปกรณ์อินพุต"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"อนุญาตให้แอปสามารถปรับพารามิเตอร์การเทียบมาตรฐานของหน้าจอสัมผัส ไม่ควรใช้สำหรับแอปทั่วไป"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"ควบคุมความยาวและอักขระที่อนุญาตให้ใช้ในรหัสผ่านการปลดล็อกหน้าจอ"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 4c54352..ec73999 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Nagbibigay-daan sa may-ari na paganahin ang app ng configuration na ibinigay ng carrier. Hindi dapat kailanganin para sa normal na apps kahit kailan."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"makinig sa mga obserbasyon sa mga kundisyon ng network"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Nagbibigay-daan sa isang application na makinig sa mga obserbasyon sa mga kundisyon ng network. Dapat na hindi kailanman kakailanganin para sa normal na apps."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"baguhin ang pag-calibrate ng input device"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Pinapayagan ang app na baguhin ang mga parameter sa pag-calibrate ng touch screen. Hindi dapat kailanganin sa normal na apps."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kontrolin ang haba at mga character na pinapayagan sa mga password sa pag-unlock ng screen."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index bf01a4e..902939e 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"İzin sahibine, operatör tarafından sağlanan yapılandırma uygulamasını çalıştırma izni verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"ağ koşullarındaki gözlemleri dinle"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Bir uygulamaya, ağ koşullarındaki gözlemleri dinleme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"giriş cihazı kalibrasyonunu değiştir"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Uygulamaya, dokunmatik ekranın kalibrasyon parametrelerini değiştirme izni verir. Normal uygulamalar için hiçbir zaman gerekmez."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Ekran kilidini açma şifrelerinde izin verilen uzunluğu ve karakterleri denetleme."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index dc79da7..fb96ca0 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Дозволяє власнику викликати надану оператором програму конфігурації. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"прослуховувати дані спостережень за станом мережі"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Дозволяє програмі прослуховувати дані спостережень за станом мережі. Ніколи не застосовується для звичайних програм."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"змінювати калібрування пристрою введення"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Програма може змінювати параметри калібрування сенсорного екрана. Ніколи не застосовується для звичайних програм."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Контролювати довжину паролів для розблокування екрана та дозволені в них символи."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 5dcf41d..60b97c3 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -256,7 +256,7 @@ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"gỡ cài đặt lối tắt"</string> <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Cho phép ứng dụng xóa lối tắt trên Màn hình chính mà không cần sự can thiệp của người dùng."</string> <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"định tuyến lại cuộc gọi đi"</string> - <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Cho phép ứng dụng xem số được quay trong một cuộc gọi đi với tùy chọn chuyển hướng cuộc gọi đến một số khác hoặc hủy cuộc gọi đó hoàn toàn."</string> + <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Cho phép ứng dụng xem số được gọi trong một cuộc gọi đi với tùy chọn chuyển hướng cuộc gọi đến một số khác hoặc hủy cuộc gọi đó hoàn toàn."</string> <string name="permlab_receiveSms" msgid="8673471768947895082">"nhận tin nhắn văn bản (SMS)"</string> <string name="permdesc_receiveSms" msgid="6424387754228766939">"Cho phép ứng dụng nhận và xử lý tin nhắn SMS. Điều này có nghĩa là ứng dụng có thể theo dõi hoặc xóa tin nhắn được gửi đến thiết bị của bạn mà không hiển thị chúng cho bạn."</string> <string name="permlab_receiveMms" msgid="1821317344668257098">"nhận tin nhắn văn bản (MMS)"</string> @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Cho phép chủ sở hữu gọi ra ứng dụng cấu hình do nhà cung cấp dịch vụ cung cấp. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"quan sát các điều kiện mạng"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Cho phép ứng dụng quan sát các điều kiện mạng. Không bao giờ cần cho ứng dụng thông thường."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"thay đổi hiệu chỉnh thiết bị đầu vào"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Cho phép ứng dụng sửa đổi các thông số hiệu chỉnh của màn hình cảm ứng. Không cần cho ứng dụng thông thường."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Kiểm soát độ dài và ký tự được phép trong mật khẩu mở khóa màn hình."</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 5a9c285..1b775e8 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允许应用调用运营商提供的配置应用。普通应用绝不需要此权限。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"监听网络状况的观测信息"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允许应用监听网络状况的观测信息。普通应用绝不需要此权限。"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"更改输入设备校准设置"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允许应用修改触摸屏的校准参数。普通应用绝不需要此权限。"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解锁密码所允许的长度和字符。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index bfffe13..1273200 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式調用流動網絡供應商提供的設定應用程式 (不建議一般應用程式使用)。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽對網絡狀況的觀察"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽對網絡狀況的觀察 (不建議一般應用程式使用)。"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"變更輸入裝置校正設定"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允許應用程式修改觸控式螢幕的校正參數,而一般應用程式並不需要作出類似修改。"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制屏幕解鎖密碼所允許的長度和字元。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"監控屏幕解鎖嘗試次數"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index d6bcb61..f4b96d0 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -256,7 +256,7 @@ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"解除安裝捷徑"</string> <string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"允許應用程式自動移除主螢幕捷徑。"</string> <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"重設撥號路徑"</string> - <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允許應用程式在撥打電話期間查看撥出的電話號碼,並選擇改撥其他號碼或完全中斷通話。"</string> + <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"允許應用程式在撥打電話期間查看撥出的電話號碼,並可選擇改撥其他號碼或中斷通話。"</string> <string name="permlab_receiveSms" msgid="8673471768947895082">"接收簡訊 (SMS)"</string> <string name="permdesc_receiveSms" msgid="6424387754228766939">"允許應用程式接收和處理簡訊。這項設定可讓應用程式監控傳送至您裝置的訊息,或在您閱讀訊息前擅自刪除訊息。"</string> <string name="permlab_receiveMms" msgid="1821317344668257098">"接收簡訊 (MMS)"</string> @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"允許應用程式叫用行動通訊業者提供的設定應用程式 (一般應用程式並不需要)。"</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"監聽網路狀況觀察資訊"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"允許應用程式監聽網路狀況觀察資訊 (一般應用程式並不需要)。"</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"變更輸入裝置校正設定"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"允許應用程式修改觸控螢幕的校正參數 (一般應用程式並不需要)。"</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"控制螢幕解鎖密碼所允許的長度和字元。"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index a44c04c..c7faf48 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -689,6 +689,8 @@ <string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Ivumela umnikazi ukuthi abuyisele uhlelo lokusebenza lokulungiselelwa. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> <string name="permlab_accessNetworkConditions" msgid="8206077447838909516">"Lalela okubonwayo kuzimo zenethiwekhi"</string> <string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"Ivumela uhlelo lokusebenza ukuthi lulalele okubonwa kuzimo zenethiwekhi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> + <string name="permlab_setInputCalibration" msgid="4902620118878467615">"guqula ukulinganisa kokufaka kwedivayisi"</string> + <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"Ivumela uhlelo lokusebenza ukuthi lushintshe imingcele yokulinganisa yesikrini esithintwayo. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string> <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string> <string name="policydesc_limitPassword" msgid="3252114203919510394">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi okuvula isikrini"</string> <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 2efbca2..0a27840 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -62,6 +62,21 @@ a reference to a Drawable resource containing the image definition. --> <attr name="icon" format="reference" /> + <!-- A Drawable resource providing an extended graphical banner for its + associated item. Use with the application tag (to supply a default + banner for all application activities), or with the activity, tag to + supply a banner for a specific activity. + + <p>The given banner will be used to display to the user a graphical + representation of an activity in the Leanback application launcher. + Since banners are displayed only in the Leanback launcher, they should + only be used with activities (and applications) that support Leanback + mode. These are activities that handle Intents of category + {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER + Intent.CATEGORY_LEANBACK_LAUNCHER}. + <p>This must be a reference to a Drawable resource containing the image definition. --> + <attr name="banner" format="reference" /> + <!-- A Drawable resource providing an extended graphical logo for its associated item. Use with the application tag (to supply a default logo for all application components), or with the activity, receiver, @@ -899,6 +914,7 @@ <attr name="theme" /> <attr name="label" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="description" /> <attr name="permission" /> @@ -982,6 +998,7 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="permissionGroup" /> <attr name="description" /> @@ -1008,6 +1025,7 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="description" /> <attr name="permissionGroupFlags" /> @@ -1040,6 +1058,7 @@ <attr name="name" /> <attr name="label" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> </declare-styleable> @@ -1306,6 +1325,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="process" /> <attr name="authorities" /> @@ -1387,6 +1407,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="permission" /> <attr name="process" /> @@ -1429,6 +1450,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="permission" /> <attr name="process" /> @@ -1463,6 +1485,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="launchMode" /> <attr name="screenOrientation" /> @@ -1526,6 +1549,7 @@ <attr name="label" /> <attr name="description" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="permission" /> <!-- Specify whether the activity-alias is enabled or not (that is, can be instantiated by the system). @@ -1597,6 +1621,7 @@ parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService"> <attr name="label" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="priority" /> </declare-styleable> @@ -1725,6 +1750,7 @@ <attr name="targetPackage" /> <attr name="label" /> <attr name="icon" /> + <attr name="banner" /> <attr name="logo" /> <attr name="handleProfiling" /> <attr name="functionalTest" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index cfd4a63..4656f32 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1212,6 +1212,10 @@ <!-- Whether UI for multi user should be shown --> <bool name="config_enableMultiUserUI">false</bool> + <!-- If true, then we do not ask user for permission for apps to connect to USB devices. + Do not set this to true for production devices. Doing so will cause you to fail CTS. --> + <bool name="config_disableUsbPermissionDialogs">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 will begin, where supported. (See android.view.ScaleGestureDetector) diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d58e8ad..25c8baa 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2088,6 +2088,13 @@ <public type="style" name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" id="0x010301e4" /> <!-- =============================================================== + Resources added in version 20 of the platform + =============================================================== --> + <eat-comment /> + + <public type="attr" name="banner" id="0x10103f2" /> + +<!-- =============================================================== Resources added in version 21 of the platform =============================================================== --> <eat-comment /> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6624da4..efa873d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -290,6 +290,7 @@ <java-symbol type="bool" name="config_forceDefaultOrientation" /> <java-symbol type="bool" name="config_wifi_batched_scan_supported" /> <java-symbol type="bool" name="config_enableMultiUserUI"/> + <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/> <java-symbol type="integer" name="config_cursorWindowSize" /> <java-symbol type="integer" name="config_extraFreeKbytesAdjust" /> diff --git a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java index 95f0e67..0e3c13a 100644 --- a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java +++ b/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java @@ -43,7 +43,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Random; +import junit.framework.Assert; + import libcore.io.IoUtils; +import libcore.io.Libcore; /** * Tests for {@link FileRotator}. @@ -367,6 +370,16 @@ public class FileRotatorTest extends AndroidTestCase { assertReadAll(rotate, "bar"); } + public void testFileSystemInaccessible() throws Exception { + File inaccessibleDir = null; + String dirPath = getContext().getFilesDir() + File.separator + "inaccessible"; + inaccessibleDir = new File(dirPath); + final FileRotator rotate = new FileRotator(inaccessibleDir, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS); + + // rotate should not throw on dir not mkdir-ed (or otherwise inaccessible) + rotate.maybeRotate(TEST_TIME); + } + private void touch(String... names) throws IOException { for (String name : names) { final OutputStream out = new FileOutputStream(new File(mBasePath, name)); diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java index f493e9a..fc2897f 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java @@ -27,14 +27,14 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiManager; import android.os.Environment; +import android.os.Handler; +import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.SystemClock; import android.provider.Settings; import android.test.InstrumentationTestCase; import android.util.Log; -import java.io.File; -import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeoutException; @@ -47,7 +47,6 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected DownloadManager mDownloadManager = null; protected String mFileType = "text/plain"; protected Context mContext = null; - protected MultipleDownloadsCompletedReceiver mReceiver = null; protected static final int DEFAULT_FILE_SIZE = 10 * 1024; // 10kb protected static final int FILE_BLOCK_READ_SIZE = 1024 * 1024; @@ -65,70 +64,9 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes - public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver { - private volatile int mNumDownloadsCompleted = 0; - private Set<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>()); + private DownloadFinishedListener mListener; + private Thread mListenerThread; - /** - * {@inheritDoc} - */ - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { - synchronized(this) { - long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); - Log.i(LOG_TAG, "Received Notification for download: " + id); - if (!downloadIds.contains(id)) { - ++mNumDownloadsCompleted; - Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + - intent.getAction() + " --> total count: " + mNumDownloadsCompleted); - downloadIds.add(id); - - DownloadManager dm = (DownloadManager)context.getSystemService( - Context.DOWNLOAD_SERVICE); - - Cursor cursor = dm.query(new Query().setFilterById(id)); - try { - if (cursor.moveToFirst()) { - int status = cursor.getInt(cursor.getColumnIndex( - DownloadManager.COLUMN_STATUS)); - Log.i(LOG_TAG, "Download status is: " + status); - } else { - fail("No status found for completed download!"); - } - } finally { - cursor.close(); - } - } else { - Log.i(LOG_TAG, "Notification for id: " + id + " has already been made."); - } - } - } - } - - /** - * Gets the number of times the {@link #onReceive} callback has been called for the - * {@link DownloadManager#ACTION_DOWNLOAD_COMPLETE} action, indicating the number of - * downloads completed thus far. - * - * @return the number of downloads completed so far. - */ - public int numDownloadsCompleted() { - return mNumDownloadsCompleted; - } - - /** - * Gets the list of download IDs. - * @return A Set<Long> with the ids of the completed downloads. - */ - public Set<Long> getDownloadIds() { - synchronized(this) { - Set<Long> returnIds = new HashSet<Long>(downloadIds); - return returnIds; - } - } - - } public static class WiFiChangedReceiver extends BroadcastReceiver { private Context mContext = null; @@ -172,13 +110,138 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** + * Broadcast receiver to listen for broadcast from DownloadManager indicating that downloads + * are finished. + */ + private class DownloadFinishedListener extends BroadcastReceiver implements Runnable { + private Handler mHandler = null; + private Looper mLooper; + private Set<Long> mFinishedDownloads = new HashSet<Long>(); + + /** + * Event loop for the thread that listens to broadcasts. + */ + @Override + public void run() { + Looper.prepare(); + synchronized (this) { + mLooper = Looper.myLooper(); + mHandler = new Handler(); + notifyAll(); + } + Looper.loop(); + } + + /** + * Handles the incoming notifications from DownloadManager. + */ + @Override + public void onReceive(Context context, Intent intent) { + if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) { + long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); + Log.i(LOG_TAG, "Received Notification for download: " + id); + synchronized (this) { + if(!mFinishedDownloads.contains(id)) { + mFinishedDownloads.add(id); + notifyAll(); + } else { + Log.i(LOG_TAG, + String.format("Notification for %d was already received", id)); + } + } + } + } + + /** + * Returns the handler for this thread. Need this to make sure that the events are handled + * in it is own thread and don't interfere with the instrumentation thread. + * @return Handler for the receiver thread. + * @throws InterruptedException + */ + private Handler getHandler() throws InterruptedException { + synchronized (this) { + if (mHandler != null) return mHandler; + while (mHandler == null) { + wait(); + } + return mHandler; + } + } + + /** + * Stops the thread that receives notification from DownloadManager. + */ + public void cancel() { + synchronized(this) { + if (mLooper != null) { + mLooper.quit(); + } + } + } + + /** + * Waits for a given download to finish, or until the timeout expires. + * @param id id of the download to wait for. + * @param timeout maximum time to wait, in milliseconds + * @return true if the download finished, false otherwise. + * @throws InterruptedException + */ + public boolean waitForDownloadToFinish(long id, long timeout) throws InterruptedException { + long startTime = SystemClock.uptimeMillis(); + synchronized (this) { + while (!mFinishedDownloads.contains(id)) { + if (SystemClock.uptimeMillis() - startTime > timeout) { + Log.i(LOG_TAG, String.format("Timeout while waiting for %d to finish", id)); + return false; + } else { + wait(timeout); + } + } + return true; + } + } + + /** + * Waits for multiple downloads to finish, or until timeout expires. + * @param ids ids of the downloads to wait for. + * @param timeout maximum time to wait, in milliseconds + * @return true of all the downloads finished, false otherwise. + * @throws InterruptedException + */ + public boolean waitForMultipleDownloadsToFinish(Set<Long> ids, long timeout) + throws InterruptedException { + long startTime = SystemClock.uptimeMillis(); + synchronized (this) { + while (!mFinishedDownloads.containsAll(ids)) { + if (SystemClock.uptimeMillis() - startTime > timeout) { + Log.i(LOG_TAG, "Timeout waiting for multiple downloads to finish"); + return false; + } else { + wait(timeout); + } + } + return true; + } + } + } + + /** * {@inheritDoc} */ @Override public void setUp() throws Exception { + super.setUp(); mContext = getInstrumentation().getContext(); mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE); - mReceiver = registerNewMultipleDownloadsReceiver(); + mListener = registerDownloadsListener(); + } + + @Override + public void tearDown() throws Exception { + mContext.unregisterReceiver(mListener); + mListener.cancel(); + mListenerThread.join(); + super.tearDown(); } /** @@ -198,12 +261,15 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { * that have completed. * * @return A new receiver that records and can be queried on how many downloads have completed. + * @throws InterruptedException */ - protected MultipleDownloadsCompletedReceiver registerNewMultipleDownloadsReceiver() { - MultipleDownloadsCompletedReceiver receiver = new MultipleDownloadsCompletedReceiver(); - mContext.registerReceiver(receiver, new IntentFilter( - DownloadManager.ACTION_DOWNLOAD_COMPLETE)); - return receiver; + protected DownloadFinishedListener registerDownloadsListener() throws InterruptedException { + DownloadFinishedListener listener = new DownloadFinishedListener(); + mListenerThread = new Thread(listener); + mListenerThread.start(); + mContext.registerReceiver(listener, new IntentFilter( + DownloadManager.ACTION_DOWNLOAD_COMPLETE), null, listener.getHandler()); + return listener; } /** @@ -283,76 +349,35 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** - * Helper to wait for a particular download to finish, or else a timeout to occur - * - * Does not wait for a receiver notification of the download. - * - * @param id The download id to query on (wait for) - */ - protected void waitForDownloadOrTimeout_skipNotification(long id) throws TimeoutException, - InterruptedException { - doWaitForDownloadsOrTimeout(new Query().setFilterById(id), - WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME); - } - - /** - * Helper to wait for a particular download to finish, or else a timeout to occur - * - * Also guarantees a notification has been posted for the download. - * - * @param id The download id to query on (wait for) - */ - protected void waitForDownloadOrTimeout(long id) throws TimeoutException, - InterruptedException { - waitForDownloadOrTimeout(id, WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME); - } - - /** - * Helper to wait for a particular download to finish, or else a timeout to occur - * - * Also guarantees a notification has been posted for the download. + * Helper to wait for a particular download to finish, or else a timeout to occur. * * @param id The download id to query on (wait for) * @param poll The amount of time to wait * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete */ - protected void waitForDownloadOrTimeout(long id, long poll, long timeoutMillis) - throws TimeoutException, InterruptedException { - doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis); - waitForReceiverNotifications(1); + protected boolean waitForDownload(long id, long timeoutMillis) + throws InterruptedException { + return mListener.waitForDownloadToFinish(id, timeoutMillis); } - /** - * Helper to wait for all downloads to finish, or else a specified timeout to occur - * - * Makes no guaranee that notifications have been posted for all downloads. - * - * @param poll The amount of time to wait - * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete - */ - protected void waitForDownloadsOrTimeout(long poll, long timeoutMillis) throws TimeoutException, - InterruptedException { - doWaitForDownloadsOrTimeout(new Query(), poll, timeoutMillis); + protected boolean waitForMultipleDownloads(Set<Long> ids, long timeout) + throws InterruptedException { + return mListener.waitForMultipleDownloadsToFinish(ids, timeout); } /** - * Helper to wait for all downloads to finish, or else a timeout to occur, but does not throw - * - * Also guarantees a notification has been posted for the download. - * - * @param id The id of the download to query against - * @param poll The amount of time to wait - * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete - * @return true if download completed successfully (didn't timeout), false otherwise + * Checks with the download manager if the give download is finished. + * @param id id of the download to check + * @return true if download is finished, false otherwise. */ - private boolean waitForDownloadOrTimeoutNoThrow(long id, long poll, long timeoutMillis) { - try { - doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis); - waitForReceiverNotifications(1); - } catch (TimeoutException e) { - return false; - } - return true; + private boolean hasDownloadFinished(long id) { + Query q = new Query(); + q.setFilterById(id); + q.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL); + Cursor cursor = mDownloadManager.query(q); + boolean finished = cursor.getCount() == 1; + cursor.close(); + return finished; } /** @@ -389,34 +414,6 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** - * Helper to wait for all downloads to finish, or else a timeout to occur - * - * @param query The query to pass to the download manager - * @param poll The poll time to wait between checks - * @param timeoutMillis The max amount of time (in ms) to wait for the download(s) to complete - */ - private void doWaitForDownloadsOrTimeout(Query query, long poll, long timeoutMillis) - throws TimeoutException { - int currentWaitTime = 0; - while (true) { - query.setFilterByStatus(DownloadManager.STATUS_PENDING | DownloadManager.STATUS_PAUSED - | DownloadManager.STATUS_RUNNING); - Cursor cursor = mDownloadManager.query(query); - - try { - if (cursor.getCount() == 0) { - Log.i(LOG_TAG, "All downloads should be done..."); - break; - } - currentWaitTime = timeoutWait(currentWaitTime, poll, timeoutMillis, - "Timed out waiting for all downloads to finish"); - } finally { - cursor.close(); - } - } - } - - /** * Synchronously waits for external store to be mounted (eg: SD Card). * * @throws InterruptedException if interrupted @@ -465,51 +462,48 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** - * Synchronously waits for our receiver to receive notification for a given number of - * downloads. + * Synchronously waits for the download manager to start incrementing the number of + * bytes downloaded so far. * - * @param targetNumber The number of notifications for unique downloads to wait for; pass in - * -1 to not wait for notification. - * @throws Exception if timed out while waiting + * @param id DownloadManager download id that needs to be checked. + * @throws Exception if timed out while waiting for the file to grow in size. */ - private void waitForReceiverNotifications(int targetNumber) throws TimeoutException { - int count = mReceiver.numDownloadsCompleted(); + protected void waitToReceiveData(long id) throws Exception { int currentWaitTime = 0; - - while (count < targetNumber) { - Log.i(LOG_TAG, "Waiting for notification of downloads..."); + long originalSize = getBytesDownloaded(id); + long currentSize = 0; + while ((currentSize = getBytesDownloaded(id)) <= originalSize) { + Log.i(LOG_TAG, String.format("orig: %d, cur: %d. Waiting for file to be written to...", + originalSize, currentSize)); currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, - MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download notifications!" - + " Received " + count + "notifications."); - count = mReceiver.numDownloadsCompleted(); + MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be written to."); } } - /** - * Synchronously waits for a file to increase in size (such as to monitor that a download is - * progressing). - * - * @param file The file whose size to track. - * @throws Exception if timed out while waiting for the file to grow in size. - */ - protected void waitForFileToGrow(File file) throws Exception { - int currentWaitTime = 0; - - // File may not even exist yet, so wait until it does (or we timeout) - while (!file.exists()) { - Log.i(LOG_TAG, "Waiting for file to exist..."); - currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, - MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be created."); + private long getBytesDownloaded(long id) { + DownloadManager.Query q = new DownloadManager.Query(); + q.setFilterById(id); + Cursor response = mDownloadManager.query(q); + if (response.getCount() < 1) { + Log.i(LOG_TAG, String.format("Query to download manager returned nothing for id %d",id)); + response.close(); + return -1; } - - // Get original file size... - long originalSize = file.length(); - - while (file.length() <= originalSize) { - Log.i(LOG_TAG, "Waiting for file to be written to..."); - currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, - MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be written to."); + while(response.moveToNext()) { + int index = response.getColumnIndex(DownloadManager.COLUMN_ID); + if (id == response.getLong(index)) { + break; + } } + int index = response.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR); + if (index < 0) { + Log.i(LOG_TAG, String.format("No downloaded bytes for id %d", id)); + response.close(); + return -1; + } + long size = response.getLong(index); + response.close(); + return size; } /** @@ -536,19 +530,6 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase { } /** - * Helper to verify an int value in a Cursor - * - * @param cursor The cursor containing the query results - * @param columnName The name of the column to query - * @param expected The expected int value - */ - private void verifyInt(Cursor cursor, String columnName, int expected) { - int index = cursor.getColumnIndex(columnName); - int actual = cursor.getInt(index); - assertEquals(expected, actual); - } - - /** * Performs a query based on ID and returns a Cursor for the query. * * @param id The id of the download in DL Manager; pass -1 to query all downloads diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java index 06c6c34..ef48a18 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java @@ -23,9 +23,6 @@ import android.os.Environment; import android.os.ParcelFileDescriptor; import android.util.Log; -import com.android.frameworks.downloadmanagertests.DownloadManagerBaseTest; -import com.android.frameworks.downloadmanagertests.DownloadManagerTestRunner; - import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; @@ -193,9 +190,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { int status = cursor.getInt(columnIndex); int currentWaitTime = 0; - // Wait until the download finishes; don't wait for a notification b/c - // the download may well have been completed before the last reboot. - waitForDownloadOrTimeout_skipNotification(dlRequest); + assertTrue(waitForDownload(dlRequest, 15 * 60 * 1000)); Log.i(LOG_TAG, "Verifying download information..."); // Verify specific info about the file (size, name, etc)... @@ -235,7 +230,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); // Rather large file, so wait up to 15 mins... - waitForDownloadOrTimeout(dlRequest, WAIT_FOR_DOWNLOAD_POLL_TIME, 15 * 60 * 1000); + assertTrue(waitForDownload(dlRequest, 15 * 60 * 1000)); Cursor cursor = getCursor(dlRequest); ParcelFileDescriptor pfd = null; @@ -289,7 +284,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // make sure we're starting to download some data... - waitForFileToGrow(downloadedFile); + waitToReceiveData(dlRequest); // download disable setWiFiStateOn(false); @@ -317,7 +312,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { Log.i(LOG_TAG, "Turning on WiFi..."); setWiFiStateOn(true); Log.i(LOG_TAG, "Waiting up to 3 minutes for download to complete..."); - waitForDownloadsOrTimeout(dlRequest, 3 * 60 * 1000); + assertTrue(waitForDownload(dlRequest, 3 * 60 * 1000)); ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { @@ -363,7 +358,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // are we making any progress? - waitForFileToGrow(downloadedFile); + waitToReceiveData(dlRequest); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); @@ -373,7 +368,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { // enable download... Log.i(LOG_TAG, "Turning on WiFi again..."); setWiFiStateOn(true); - waitForFileToGrow(downloadedFile); + waitToReceiveData(dlRequest); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); @@ -385,7 +380,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { setWiFiStateOn(true); Log.i(LOG_TAG, "Waiting up to 3 minutes for download to complete..."); - waitForDownloadsOrTimeout(dlRequest, 3 * 60 * 1000); + assertTrue(waitForDownload(dlRequest, 3 * 60 * 1000)); ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { @@ -433,7 +428,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // are we making any progress? - waitForFileToGrow(downloadedFile); + waitToReceiveData(dlRequest); // download disable Log.i(LOG_TAG, "Turning on Airplane mode..."); @@ -444,7 +439,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { Log.i(LOG_TAG, "Turning off Airplane mode..."); setAirplaneModeOn(false); // make sure we're starting to download some data... - waitForFileToGrow(downloadedFile); + waitToReceiveData(dlRequest); // reenable the connection to start up the download again Log.i(LOG_TAG, "Turning on Airplane mode again..."); @@ -456,7 +451,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { setAirplaneModeOn(false); Log.i(LOG_TAG, "Waiting up to 3 minutes for donwload to complete..."); - waitForDownloadsOrTimeout(dlRequest, 180 * 1000); // wait up to 3 mins before timeout + assertTrue(waitForDownload(dlRequest, 180 * 1000)); // wait up to 3 mins before timeout ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { @@ -476,7 +471,6 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { public void runDownloadMultipleSimultaneously() throws Exception { final int TOTAL_DOWNLOADS = 15; HashSet<Long> downloadIds = new HashSet<Long>(TOTAL_DOWNLOADS); - MultipleDownloadsCompletedReceiver receiver = registerNewMultipleDownloadsReceiver(); // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); @@ -494,8 +488,7 @@ public class DownloadManagerTestApp extends DownloadManagerBaseTest { downloadIds.add(dlRequest); } - waitForDownloadsOrTimeout(DEFAULT_WAIT_POLL_TIME, 15 * 60 * 2000); // wait 15 mins max - assertEquals(TOTAL_DOWNLOADS, receiver.numDownloadsCompleted()); + assertTrue(waitForMultipleDownloads(downloadIds, 15 * 60 * 2000)); // wait 15 mins max } finally { removeAllCurrentDownloads(); } diff --git a/docs/html/images/screens_support/avds-config.png b/docs/html/images/screens_support/avds-config.png Binary files differindex 97bd5f6..e609447 100644 --- a/docs/html/images/screens_support/avds-config.png +++ b/docs/html/images/screens_support/avds-config.png diff --git a/docs/html/images/tools/as-camera-icon.png b/docs/html/images/tools/as-camera-icon.png Binary files differnew file mode 100644 index 0000000..419a88d --- /dev/null +++ b/docs/html/images/tools/as-camera-icon.png diff --git a/docs/html/images/tools/as-error.png b/docs/html/images/tools/as-error.png Binary files differnew file mode 100644 index 0000000..8865f54 --- /dev/null +++ b/docs/html/images/tools/as-error.png diff --git a/docs/html/images/tools/as-fr-device.png b/docs/html/images/tools/as-fr-device.png Binary files differnew file mode 100644 index 0000000..aec3bce --- /dev/null +++ b/docs/html/images/tools/as-fr-device.png diff --git a/docs/html/images/tools/as-fr-icon.png b/docs/html/images/tools/as-fr-icon.png Binary files differnew file mode 100644 index 0000000..9252ca1 --- /dev/null +++ b/docs/html/images/tools/as-fr-icon.png diff --git a/docs/html/images/tools/as-frag-ex.png b/docs/html/images/tools/as-frag-ex.png Binary files differnew file mode 100644 index 0000000..775fa5e --- /dev/null +++ b/docs/html/images/tools/as-frag-ex.png diff --git a/docs/html/images/tools/as-grid-layout.png b/docs/html/images/tools/as-grid-layout.png Binary files differnew file mode 100644 index 0000000..41b933a --- /dev/null +++ b/docs/html/images/tools/as-grid-layout.png diff --git a/docs/html/images/tools/as-i18n-icon.png b/docs/html/images/tools/as-i18n-icon.png Binary files differnew file mode 100644 index 0000000..d35568f --- /dev/null +++ b/docs/html/images/tools/as-i18n-icon.png diff --git a/docs/html/images/tools/as-preview-chrome.png b/docs/html/images/tools/as-preview-chrome.png Binary files differnew file mode 100644 index 0000000..716b8d7 --- /dev/null +++ b/docs/html/images/tools/as-preview-chrome.png diff --git a/docs/html/images/tools/as-preview-icon.png b/docs/html/images/tools/as-preview-icon.png Binary files differnew file mode 100644 index 0000000..59c7644 --- /dev/null +++ b/docs/html/images/tools/as-preview-icon.png diff --git a/docs/html/images/tools/as-preview-nochrome.png b/docs/html/images/tools/as-preview-nochrome.png Binary files differnew file mode 100644 index 0000000..1011e08 --- /dev/null +++ b/docs/html/images/tools/as-preview-nochrome.png diff --git a/docs/html/images/tools/as-theme-db.png b/docs/html/images/tools/as-theme-db.png Binary files differnew file mode 100644 index 0000000..beade0d --- /dev/null +++ b/docs/html/images/tools/as-theme-db.png diff --git a/docs/html/images/tools/as-theme-icon.png b/docs/html/images/tools/as-theme-icon.png Binary files differnew file mode 100644 index 0000000..0e5fdf0 --- /dev/null +++ b/docs/html/images/tools/as-theme-icon.png diff --git a/docs/html/images/training/firstapp/adt-firstapp-setup.png b/docs/html/images/training/firstapp/adt-firstapp-setup.png Binary files differindex bf95285..05e147d 100644 --- a/docs/html/images/training/firstapp/adt-firstapp-setup.png +++ b/docs/html/images/training/firstapp/adt-firstapp-setup.png diff --git a/docs/html/images/training/firstapp/adt-new-activity.png b/docs/html/images/training/firstapp/adt-new-activity.png Binary files differindex c396793..2c32dcc 100644 --- a/docs/html/images/training/firstapp/adt-new-activity.png +++ b/docs/html/images/training/firstapp/adt-new-activity.png diff --git a/docs/html/images/training/firstapp/edittext_gravity.png b/docs/html/images/training/firstapp/edittext_gravity.png Binary files differindex f78e676..bc4f7ee 100644 --- a/docs/html/images/training/firstapp/edittext_gravity.png +++ b/docs/html/images/training/firstapp/edittext_gravity.png diff --git a/docs/html/images/training/firstapp/edittext_wrap.png b/docs/html/images/training/firstapp/edittext_wrap.png Binary files differindex 156776d..fe56731 100644 --- a/docs/html/images/training/firstapp/edittext_wrap.png +++ b/docs/html/images/training/firstapp/edittext_wrap.png diff --git a/docs/html/images/training/firstapp/firstapp.png b/docs/html/images/training/firstapp/firstapp.png Binary files differindex d69cd20..581e000 100644 --- a/docs/html/images/training/firstapp/firstapp.png +++ b/docs/html/images/training/firstapp/firstapp.png diff --git a/docs/html/index.jd b/docs/html/index.jd index 5d1788a..e901652 100644 --- a/docs/html/index.jd +++ b/docs/html/index.jd @@ -22,12 +22,13 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3 <script src="//ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script> <div style="box-shadow: 3px 10px 18px 1px #999;width:600px;height:336px"> <div id="ytapiplayer"> - <a href="http://www.youtube.com/watch?v=WWArLD6nqrk"><img width=600 src="{@docRoot}images/video-kiwi.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. --> + <a href="http://www.youtube.com/watch?v=i2uvYI6blEE"><img width=600 + src="https://i1.ytimg.com/vi/i2uvYI6blEE/maxresdefault.jpg"></a><!--You need Flash player 8+ and JavaScript enabled to view this video. --> </div> <script type="text/javascript"> var params = { allowScriptAccess: "always" }; var atts = { id: "ytapiplayer" }; - swfobject.embedSWF("//www.youtube.com/v/WWArLD6nqrk?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1", + swfobject.embedSWF("//www.youtube.com/v/i2uvYI6blEE?enablejsapi=1&playerapiid=ytplayer&version=3&HD=1;rel=0;showinfo=0;modestbranding;origin=developer.android.com;autohide=1", "ytapiplayer", "600", "336", "8", null, null, params, atts); // Callback used to pause/resume carousel based on video state @@ -56,9 +57,8 @@ page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3 </div> </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 had five titles in the top 25 grossing on Google Play. Hear how Google Play - has helped them double revenue every six months.</p> + <h1 style="white-space:nowrap;line-height:1.2em;">Developer Story: <br />Box Inc.</h1> + <p>Box is a cloud-based platform and app for users to share business information. See how they got over 5 million downloads by leveraging the flexibility in the Android platform.</p> <p><a href="{@docRoot}distribute/googleplay/spotlight/index.html" class="button">Watch more videos </a></p> </div> </li> diff --git a/docs/html/sdk/installing/studio-layout.jd b/docs/html/sdk/installing/studio-layout.jd new file mode 100644 index 0000000..f0e5d59 --- /dev/null +++ b/docs/html/sdk/installing/studio-layout.jd @@ -0,0 +1,148 @@ +page.title=Using the Layout Editor + +@jd:body + +<div id="qv-wrapper"> +<div id="qv"> +<h2>See also</h2> +<ul> +<li><a href="{@docRoot}sdk/installing/studio.html"> +Getting Started with Android Studio</a></li> +<li><a href="{@docRoot}sdk/installing/studio-tips.html"> +Android Studio Tips and Tricks</a></li> +<li><a href="{@docRoot}sdk/installing/migrate.html"> +Migrating from Eclipse</a></li> +</div> +</div> + +<a class="notice-developers-video" +href="https://developers.google.com/events/io/sessions/324603352"> +<div> + <h3>Video</h3> + <p>What's New in Android Developer Tools</p> +</div> +</a> + +<p>Android Studio offers an advanced layout editor that allows you to drag-and-drop widgets +into your layout and preview your layout while editing the XML.</p> + +<p>Within the layout editor, you can switch between the <strong>Text</strong> view, where +you edit the XML file as text, and the <strong>Design</strong> view. Just click the +appropriate tab at the bottom of the window to display the desired editor.</p> + +<h2>Editing in the Text View</h2> + +<p>You can use the <strong>Text</strong> view to edit your layout file. This section describes +some of the features that are available in the <strong>Text</strong> view.</p> + +<h3>Preview</h3> + +<p>While editing in the <strong>Text</strong> view, you can preview the layout on devices +by opening the <strong>Preview</strong> pane available on the right side of the window. +Within the <strong>Preview</strong> pane, you can modify the preview by changing various +options at the top of the pane, including the preview device, layout theme, platform +version and more. To see a preview of how your app would look with a particular device +skin, click the preview icon +<img src="{@docRoot}images/tools/as-preview-icon.png" style="vertical-align:bottom;margin:0;height:19px" /> +and choose the desired device, such as Nexus 4:</p> + +<img src="{@docRoot}images/tools/as-preview-chrome.png" alt="" /> +<p class="img-caption"><strong>Figure 1.</strong> Previewing your app.</p> + +<p>To preview the layout on multiple devices simultaneously, select <strong>Preview All +Screen Sizes</strong> from the device drop-down. </p> + +<p>When you click in the preview image, the layout editor highlights the corresponding +section in the XML, and vice-versa.</p> + +<h3>Interactive error detection and recovery</h3> + +<p>As you edit the <strong>Text</strong> view of your layout XML file, Android Studio flags +typos and offers assistance.</p> + +<p>For example, suppose you are adding a button, and you misspell it as "Buttonn". +Android Studio helps you to correct it by displaying an error such as the following, +where you can click on "Change to Button" to fix the error in the XML file:</p> + +<img src="{@docRoot}images/tools/as-error.png" alt="" /> + +<p class="img-caption"><strong>Figure 2.</strong> Flagging errors.</p> + +<p>Android Studio also prompts you to supply missing information. For example, suppose you +start adding a fragment to your layout XML file. First of all, Android Studio displays +auto-complete suggestions as you type. Once it becomes clear that you are adding a fragment, +Android Studio displays an error panel with links that you can click to supply the missing +attributes. Clicking "Automatically add all missing attributes" in this case +does just that—it completes the fragment definition in your layout XML file:</p> + +<img src="{@docRoot}images/tools/as-frag-ex.png" alt="" /> + +<p class="img-caption"><strong>Figure 3.</strong> Supplying missing information</p> + +<h3>Picking a theme</h3> + +<p>To pick a theme for your app, click the Theme icon +<img src="{@docRoot}images/tools/as-theme-icon.png" style="vertical-align:bottom;margin:0;height:19px" />. +</p> + +<p>This displays the <strong>Select Theme</strong> dialog, where you can search for a +particular theme and/or select one from the list on the right hand side. The theme you +choose will be reflected in the previewed image.</p> + +<img src="{@docRoot}images/tools/as-theme-db.png" alt="" /> + +<p class="img-caption"><strong>Figure 4.</strong> Specifying a theme.</p> + +<h3>Localization</h3> + +<p>Android Studio provides built-in localization support. When you click the +localization icon +<img src="{@docRoot}images/tools/as-i18n-icon.png" style="vertical-align:bottom;margin:0;height:19px" />, +you can select a particular locale, add and edit translations, preview the locales your +app supports (all locales or just a single locale), and preview right-to-left layout for +languages that are RTL.</p> + +<p>See <a href="{@docRoot}training/basics/supporting-devices/languages.html">Supporting +Different Languages</a> for a description of how to support different locales in your app.</p> +<p>For example, here is a preview of a "Hello World" app for the +<img src="{@docRoot}images/tools/as-fr-icon.png" style="vertical-align:bottom;margin:0;height:19px" /> +locale:</p> + +<img src="{@docRoot}images/tools/as-fr-device.png" alt="" /> +<p class="img-caption"><strong>Figure 5.</strong> Previewing locales.</p> + +<h2>Editing in the Design View</h2> + +<p>You can switch to the graphical editor by clicking <strong>Design</strong> at the +bottom of the window. While editing in the <strong>Design</strong> view, you can show and +hide the widgets available to drag-and-drop by clicking <strong>Palette</strong> on the +left side of the window. Clicking <strong>Designer</strong> on the right side of the +window reveals a panel with a layout hierarchy and a list of properties for each view in +the layout.</p> + +<p>When you drag a widget into the graphical layout for your app, the display changes to +help you place the widget. What you see depends on the type of layout. For example, if +you're dragging a widget into a {@link android.widget.FrameLayout}, it displays a grid to +help you place the widget, as shown in figure 6:</p> + +<img src="{@docRoot}images/tools/as-grid-layout.png" alt="" /> + +<p class="img-caption"><strong>Figure 6.</strong> Using the grid layout to place a widget.</p> + +<p>Within the graphical editor, you can rearrange your app's UI by dragging widgets to +the desired location.</p> + +<h3>Taking a snapshot</h3> + +<p>When you run your app on a connected device, you can take a snapshot of it by clicking +the camera icon +<img src="{@docRoot}images/tools/as-camera-icon.png" style="vertical-align:bottom;margin:0;height:19px" /> +to the left of the logging +panel (at the bottom of the window by default). This takes a snapshot of your running app +(or whatever is currently displayed on your device) and displays it in a window. Check +<strong>Frame Screenshot</strong> to show your screenshot within the device skin of your +choice. You can also specify whether you want the image to have screen glare and/or a drop +shadow. Once you have the desired effect, you can save the image.</p> + +<p>You can use the same process to create a snapshot of your app's preview. Just click the +camera icon in the preview area and follow the steps for adding a device skin.</p> diff --git a/docs/html/sdk/installing/studio.jd b/docs/html/sdk/installing/studio.jd index 5a7e270..feb7a6e 100644 --- a/docs/html/sdk/installing/studio.jd +++ b/docs/html/sdk/installing/studio.jd @@ -318,6 +318,12 @@ information about how to resolve them.</p> <h2 id="Installing">Installing Android Studio</h2> +<p>Android Studio requires JDK 6 or greater (JRE alone is not sufficient). To check if you +have JDK installed (and which version), open a terminal and type <code>javac -version</code>. +If JDK is not available or the version is lower than 6, +<a href="http://www.oracle.com/technetwork/java/javase/downloads/index.html">download +JDK from here</a>.</p> +<p>To install Android Studio:</p> <ol> <li>Download the <strong>Android Studio</strong> package from above.</li> <li>Install Android Studio and the SDK tools: diff --git a/docs/html/tools/help/logcat.jd b/docs/html/tools/help/logcat.jd index ede1905..b30971e 100644 --- a/docs/html/tools/help/logcat.jd +++ b/docs/html/tools/help/logcat.jd @@ -45,7 +45,7 @@ $ adb shell <tr> <td><code>-b <buffer></code></td> - <td>Loads an alternate log buffer for viewing, such as <code>event</code> or + <td>Loads an alternate log buffer for viewing, such as <code>events</code> or <code>radio</code>. The <code>main</code> buffer is used by default. See <a href= "{@docRoot}tools/debugging/debugging-log.html#alternativeBuffers">Viewing Alternative Log Buffers</a>.</td> </tr> diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs index a8424e6..382165c 100644 --- a/docs/html/tools/tools_toc.cs +++ b/docs/html/tools/tools_toc.cs @@ -34,7 +34,9 @@ Migrating from Eclipse</a></li> <li><a href="<?cs var:toroot ?>sdk/installing/studio-tips.html"> Tips and Tricks</a></li> - </ul> + <li><a href="<?cs var:toroot ?>sdk/installing/studio-layout.html"> + Using the Layout Editor</a></li> + </ul> </li> <li><a href="<?cs var:toroot ?>sdk/exploring.html"> <span class="en">Exploring the SDK</span></a></li> diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd index 2615bee..179b3ac 100644 --- a/docs/html/training/basics/firstapp/building-ui.jd +++ b/docs/html/training/basics/firstapp/building-ui.jd @@ -75,16 +75,16 @@ content of the text field to another activity.</p> <h2 id="LinearLayout">Create a Linear Layout</h2> -<p>Open the <code>activity_main.xml</code> file from the <code>res/layout/</code> +<p>Open the <code>fragment_main.xml</code> file from the <code>res/layout/</code> directory.</p> <p class="note"><strong>Note:</strong> In Eclipse, when you open a layout file, you’re first shown the Graphical Layout editor. This is an editor that helps you build layouts using WYSIWYG tools. For this -lesson, you’re going to work directly with the XML, so click the <em>activity_main.xml</em> tab at +lesson, you’re going to work directly with the XML, so click the <em>fragment_main.xml</em> tab at the bottom of the screen to open the XML editor.</p> <p>The BlankActivity template you chose when you created this project includes the -<code>activity_main.xml</code> file with a {@link +<code>fragment_main.xml</code> file with a {@link android.widget.RelativeLayout} root view and a {@link android.widget.TextView} child view.</p> <p>First, delete the {@link android.widget.TextView <TextView>} element and change the {@link @@ -95,7 +95,6 @@ android:orientation}</a> attribute and set it to <code>"horizontal"</code>. The result looks like this:</p> <pre> -<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd index 9516e37..50485db 100644 --- a/docs/html/training/basics/firstapp/creating-project.jd +++ b/docs/html/training/basics/firstapp/creating-project.jd @@ -120,8 +120,8 @@ devices.</li> <strong>Finish</strong>.</li> </ol> -<p>Your Android project is now set up with some default files and you’re ready to begin -building the app. Continue to the <a href="running-app.html">next lesson</a>.</p> +<p>Your Android project is now a basic "Hello World" app that contains some default files. +To run the app, continue to the <a href="running-app.html">next lesson</a>.</p> @@ -155,8 +155,8 @@ and replace projects.</p></li> </ol> -<p>Your Android project is now set up with several default configurations and you’re ready to begin -building the app. Continue to the <a href="running-app.html">next lesson</a>.</p> +<p>Your Android project is now a basic "Hello World" app that contains some default files. +To run the app, continue to the <a href="running-app.html">next lesson</a>.</p> <p class="note"><strong>Tip:</strong> Add the <code>platform-tools/</code> as well as the <code>tools/</code> directory to your <code>PATH</code> environment variable.</p> diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd index 999d399..23cedba 100644 --- a/docs/html/training/basics/firstapp/running-app.jd +++ b/docs/html/training/basics/firstapp/running-app.jd @@ -62,7 +62,7 @@ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code andro attributes. For your first app, it should look like this:</p> <pre> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... > - <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> + <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19" /> ... </manifest> </pre> diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd index 712eabc..9aa25a3 100644 --- a/docs/html/training/basics/firstapp/starting-activity.jd +++ b/docs/html/training/basics/firstapp/starting-activity.jd @@ -45,7 +45,7 @@ starts a new activity when the user clicks the Send button.</p> <h2 id="RespondToButton">Respond to the Send Button</h2> -<p>To respond to the button's on-click event, open the <code>activity_main.xml</code> +<p>To respond to the button's on-click event, open the <code>fragment_main.xml</code> layout file and add the <a href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a> attribute to the {@link android.widget.Button <Button>} element:</p> @@ -73,14 +73,6 @@ public void sendMessage(View view) { } </pre> -<p>This requires that you import the {@link android.view.View} class:</p> -<pre> -import android.view.View; -</pre> - -<p class="note"><strong>Tip:</strong> In Eclipse, press Ctrl + Shift + O to import missing classes -(Cmd + Shift + O on Mac).</p> - <p>In order for the system to match this method to the method name given to <a href="{@docRoot}reference/android/view/View.html#attr_android:onClick">{@code android:onClick}</a>, the signature must be exactly as shown. Specifically, the method must:</p> @@ -111,6 +103,14 @@ an activity called {@code DisplayMessageActivity}:</p> Intent intent = new Intent(this, DisplayMessageActivity.class); </pre> +<p>This requires that you import the {@link android.content.Intent} class:</p> +<pre> +import android.content.Intent; +</pre> + +<p class="note"><strong>Tip:</strong> In Eclipse, press Ctrl + Shift + O to import missing classes +(Cmd + Shift + O on Mac).</p> + <p>The constructor used here takes two parameters:</p> <ul> <li>A {@link @@ -151,9 +151,8 @@ intent.putExtra(EXTRA_MESSAGE, message); </pre> <p class="note"><strong>Note:</strong> -You now need import statements for <code>android.content.Intent</code> -and <code>android.widget.EditText</code>. You'll define the <code>EXTRA_MESSAGE</code> -constant in a moment.</p> +You now need an import statement for <code>android.widget.EditText</code>. +You'll define the <code>EXTRA_MESSAGE</code> constant in a moment.</p> <p>An {@link android.content.Intent} can carry a collection of various data types as key-value pairs called <em>extras</em>. The {@link android.content.Intent#putExtra putExtra()} method takes the @@ -165,7 +164,7 @@ public constant. So add the {@code EXTRA_MESSAGE} definition to the top of the { MainActivity} class:</p> <pre> -public class MainActivity extends Activity { +public class MainActivity extends ActionBarActivity { public final static String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE"; ... } @@ -223,6 +222,7 @@ work.</p> <li><strong>Project</strong>: MyFirstApp</li> <li><strong>Activity Name</strong>: DisplayMessageActivity</li> <li><strong>Layout Name</strong>: activity_display_message</li> + <li><strong>Fragment Layout Name</strong>: fragment_display_message</li> <li><strong>Title</strong>: My Message</li> <li><strong>Hierarchial Parent</strong>: com.example.myfirstapp.MainActivity</li> <li><strong>Navigation Type</strong>: None</li> @@ -240,49 +240,65 @@ activity:</p> <ul> <li>The class already includes an implementation of the required {@link android.app.Activity#onCreate onCreate()} -method.</li> +method. You will update the implementation of this method later.</li> <li>There's also an implementation of the {@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()} method, but you won't need it for this app so you can remove it.</li> <li>There's also an implementation of {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} which handles the behavior for the action bar's <em>Up</em> behavior. Keep this one the way it is.</li> + <li>There's also a <code>PlaceholderFragment</code> class that extends +{@link android.app.Fragment}. You will not need this class in the final version of this +activity.</li> </ul> -<p>Because the {@link android.app.ActionBar} APIs are available only on {@link -android.os.Build.VERSION_CODES#HONEYCOMB} (API level 11) and higher, you must add a condition -around the {@link android.app.Activity#getActionBar()} method to check the current platform version. -Additionally, you must add the {@code @SuppressLint("NewApi")} tag to the -{@link android.app.Activity#onCreate onCreate()} method to avoid <a -href="{@docRoot}tools/help/lint.html">lint</a> errors.</p> +<p>Fragments decompose application functionality and UI into reusable modules. For more +information on fragments, see the <a href="{@docRoot}guide/components/fragments.html">Fragments +API Guide</a>. The final version of this activity does not use fragments.</p> <p>The {@code DisplayMessageActivity} class should now look like this:</p> <pre> -public class DisplayMessageActivity extends Activity { +public class DisplayMessageActivity extends ActionBarActivity { - @SuppressLint("NewApi") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_display_message); - // Make sure we're running on Honeycomb or higher to use ActionBar APIs - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - // Show the Up button in the action bar. - getActionBar().setDisplayHomeAsUpEnabled(true); + if (savedInstanceState == null) { + getSupportFragmentManager().beginTransaction() + .add(R.id.container, new PlaceholderFragment()).commit(); } } @Override public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - NavUtils.navigateUpFromSameTask(this); + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } + + /** + * A placeholder fragment containing a simple view. + */ + public static class PlaceholderFragment extends Fragment { + + public PlaceholderFragment() { } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_display_message, + container, false); + return rootView; + } + } } </pre> @@ -422,7 +438,7 @@ public void onCreate(Bundle savedInstanceState) { <img src="{@docRoot}images/training/firstapp/firstapp.png" /> <p class="img-caption"><strong>Figure 2.</strong> Both activities in the final app, running -on Android 4.0. +on Android 4.4. <p>That's it, you've built your first Android app!</p> diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index 2cc7a84..eeff4c0 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -38,6 +38,7 @@ ifeq ($(USE_OPENGL_RENDERER),true) Program.cpp \ ProgramCache.cpp \ RenderBufferCache.cpp \ + RenderProperties.cpp \ ResourceCache.cpp \ ShadowTessellator.cpp \ SkiaShader.cpp \ diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp index 69d3328..2dfc873 100644 --- a/libs/hwui/Caches.cpp +++ b/libs/hwui/Caches.cpp @@ -315,7 +315,7 @@ void Caches::clearGarbage() { pathCache.clearGarbage(); patchCache.clearGarbage(); - Vector<DisplayList*> displayLists; + Vector<RenderNode*> displayLists; Vector<Layer*> layers; { // scope for the lock @@ -328,7 +328,7 @@ void Caches::clearGarbage() { size_t count = displayLists.size(); for (size_t i = 0; i < count; i++) { - DisplayList* displayList = displayLists.itemAt(i); + RenderNode* displayList = displayLists.itemAt(i); delete displayList; } @@ -345,7 +345,7 @@ void Caches::deleteLayerDeferred(Layer* layer) { mLayerGarbage.push(layer); } -void Caches::deleteDisplayListDeferred(DisplayList* displayList) { +void Caches::deleteDisplayListDeferred(RenderNode* displayList) { Mutex::Autolock _l(mGarbageLock); mDisplayListGarbage.push(displayList); } diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h index 6f3d8fb..50c5fef 100644 --- a/libs/hwui/Caches.h +++ b/libs/hwui/Caches.h @@ -102,7 +102,7 @@ struct CacheLogger { // Caches /////////////////////////////////////////////////////////////////////////////// -class DisplayList; +class RenderNode; class ANDROID_API Caches: public Singleton<Caches> { Caches(); @@ -169,7 +169,7 @@ public: /* * Can be used to delete a display list from a non EGL thread. */ - void deleteDisplayListDeferred(DisplayList* layer); + void deleteDisplayListDeferred(RenderNode* layer); /** * Binds the VBO used to render simple textured quads. @@ -420,7 +420,7 @@ private: mutable Mutex mGarbageLock; Vector<Layer*> mLayerGarbage; - Vector<DisplayList*> mDisplayListGarbage; + Vector<RenderNode*> mDisplayListGarbage; DebugLevel mDebugLevel; bool mInitialized; diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 7a2e288..7a83967 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -54,7 +54,7 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { SkRefCnt_SafeAssign(mColorFilter, colorFilter); } -void DeferredLayerUpdater::setDisplayList(DisplayList* displayList, +void DeferredLayerUpdater::setDisplayList(RenderNode* displayList, int left, int top, int right, int bottom) { mDisplayList = displayList; if (mDirtyRect.isEmpty()) { diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index 65f225c..d124cde 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -72,7 +72,7 @@ public: mTransform = matrix ? new SkMatrix(*matrix) : 0; } - ANDROID_API void setDisplayList(DisplayList* displayList, + ANDROID_API void setDisplayList(RenderNode* displayList, int left, int top, int right, int bottom); ANDROID_API void setPaint(const SkPaint* paint); @@ -101,7 +101,7 @@ private: // Layer type specific properties // displayList and surfaceTexture are mutually exclusive, only 1 may be set // dirtyRect is only valid if displayList is set - DisplayList* mDisplayList; + RenderNode* mDisplayList; Rect mDirtyRect; sp<GLConsumer> mSurfaceTexture; SkMatrix* mTransform; diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp index b954c1f..346fbce 100644 --- a/libs/hwui/DisplayList.cpp +++ b/libs/hwui/DisplayList.cpp @@ -29,7 +29,7 @@ namespace android { namespace uirenderer { -void DisplayList::outputLogBuffer(int fd) { +void RenderNode::outputLogBuffer(int fd) { DisplayListLogBuffer& logBuffer = DisplayListLogBuffer::getInstance(); if (logBuffer.isEmpty()) { return; @@ -48,65 +48,24 @@ void DisplayList::outputLogBuffer(int fd) { fflush(file); } -DisplayList::DisplayList() : - mDisplayListData(0), mDestroyed(false), mTransformMatrix(NULL), mTransformCamera(NULL), - mTransformMatrix3D(NULL), mStaticMatrix(NULL), mAnimationMatrix(NULL) { - - mLeft = 0; - mTop = 0; - mRight = 0; - mBottom = 0; - mClipToBounds = true; - mIsolatedZVolume = true; - mProjectBackwards = false; - mProjectionReceiver = false; - mOutline.rewind(); - mClipToOutline = false; - mCastsShadow = false; - mUsesGlobalCamera = false; - mAlpha = 1; - mHasOverlappingRendering = true; - mTranslationX = 0; - mTranslationY = 0; - mTranslationZ = 0; - mRotation = 0; - mRotationX = 0; - mRotationY= 0; - mScaleX = 1; - mScaleY = 1; - mPivotX = 0; - mPivotY = 0; - mCameraDistance = 0; - mMatrixDirty = false; - mMatrixFlags = 0; - mPrevWidth = -1; - mPrevHeight = -1; - mWidth = 0; - mHeight = 0; - mPivotExplicitlySet = false; - mCaching = false; +RenderNode::RenderNode() : mDestroyed(false), mDisplayListData(0) { } -DisplayList::~DisplayList() { +RenderNode::~RenderNode() { LOG_ALWAYS_FATAL_IF(mDestroyed, "Double destroyed DisplayList %p", this); mDestroyed = true; delete mDisplayListData; - delete mTransformMatrix; - delete mTransformCamera; - delete mTransformMatrix3D; - delete mStaticMatrix; - delete mAnimationMatrix; } -void DisplayList::destroyDisplayListDeferred(DisplayList* displayList) { +void RenderNode::destroyDisplayListDeferred(RenderNode* displayList) { if (displayList) { DISPLAY_LIST_LOGD("Deferring display list destruction"); Caches::getInstance().deleteDisplayListDeferred(displayList); } } -void DisplayList::setData(DisplayListData* data) { +void RenderNode::setData(DisplayListData* data) { delete mDisplayListData; mDisplayListData = data; if (mDisplayListData) { @@ -118,7 +77,7 @@ void DisplayList::setData(DisplayListData* data) { * This function is a simplified version of replay(), where we simply retrieve and log the * display list. This function should remain in sync with the replay() function. */ -void DisplayList::output(uint32_t level) { +void RenderNode::output(uint32_t level) { ALOGD("%*sStart display list (%p, %s, render=%d)", (level - 1) * 2, "", this, mName.string(), isRenderable()); ALOGD("%*s%s %d", level * 2, "", "Save", @@ -133,97 +92,35 @@ void DisplayList::output(uint32_t level) { ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, mName.string()); } -float DisplayList::getPivotX() { - updateMatrix(); - return mPivotX; -} - -float DisplayList::getPivotY() { - updateMatrix(); - return mPivotY; -} - -void DisplayList::updateMatrix() { - if (mMatrixDirty) { - // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform - // to a pure translate. This is safe because the matrix isn't read in pure translate cases. - if (mMatrixFlags && mMatrixFlags != TRANSLATION) { - if (!mTransformMatrix) { - // only allocate a matrix if we have a complex transform - mTransformMatrix = new Matrix4(); - } - if (!mPivotExplicitlySet) { - if (mWidth != mPrevWidth || mHeight != mPrevHeight) { - mPrevWidth = mWidth; - mPrevHeight = mHeight; - mPivotX = mPrevWidth / 2.0f; - mPivotY = mPrevHeight / 2.0f; - } - } - - if ((mMatrixFlags & ROTATION_3D) == 0) { - mTransformMatrix->loadTranslate( - mPivotX + mTranslationX, - mPivotY + mTranslationY, - 0); - mTransformMatrix->rotate(mRotation, 0, 0, 1); - mTransformMatrix->scale(mScaleX, mScaleY, 1); - mTransformMatrix->translate(-mPivotX, -mPivotY); - } else { - if (!mTransformCamera) { - mTransformCamera = new Sk3DView(); - mTransformMatrix3D = new SkMatrix(); - } - SkMatrix transformMatrix; - transformMatrix.reset(); - mTransformCamera->save(); - transformMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY); - mTransformCamera->rotateX(mRotationX); - mTransformCamera->rotateY(mRotationY); - mTransformCamera->rotateZ(-mRotation); - mTransformCamera->getMatrix(mTransformMatrix3D); - mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY); - mTransformMatrix3D->postTranslate(mPivotX + mTranslationX, - mPivotY + mTranslationY); - transformMatrix.postConcat(*mTransformMatrix3D); - mTransformCamera->restore(); - - mTransformMatrix->load(transformMatrix); - } - } - mMatrixDirty = false; - } -} - -void DisplayList::outputViewProperties(const int level) { - updateMatrix(); - if (mLeft != 0 || mTop != 0) { - ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mLeft, mTop); +void RenderNode::outputViewProperties(const int level) { + properties().updateMatrix(); + if (properties().mLeft != 0 || properties().mTop != 0) { + ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", properties().mLeft, properties().mTop); } - if (mStaticMatrix) { + if (properties().mStaticMatrix) { ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING, - level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix)); + level * 2, "", properties().mStaticMatrix, SK_MATRIX_ARGS(properties().mStaticMatrix)); } - if (mAnimationMatrix) { + if (properties().mAnimationMatrix) { ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING, - level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix)); + level * 2, "", properties().mAnimationMatrix, SK_MATRIX_ARGS(properties().mAnimationMatrix)); } - if (mMatrixFlags != 0) { - if (mMatrixFlags == TRANSLATION) { + if (properties().mMatrixFlags != 0) { + if (properties().mMatrixFlags == TRANSLATION) { ALOGD("%*sTranslate %.2f, %.2f, %.2f", - level * 2, "", mTranslationX, mTranslationY, mTranslationZ); + level * 2, "", properties().mTranslationX, properties().mTranslationY, properties().mTranslationZ); } else { ALOGD("%*sConcatMatrix %p: " MATRIX_4_STRING, - level * 2, "", mTransformMatrix, MATRIX_4_ARGS(mTransformMatrix)); + level * 2, "", properties().mTransformMatrix, MATRIX_4_ARGS(properties().mTransformMatrix)); } } - bool clipToBoundsNeeded = mCaching ? false : mClipToBounds; - if (mAlpha < 1) { - if (mCaching) { - ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha); - } else if (!mHasOverlappingRendering) { - ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha); + bool clipToBoundsNeeded = properties().mCaching ? false : properties().mClipToBounds; + if (properties().mAlpha < 1) { + if (properties().mCaching) { + ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", properties().mAlpha); + } else if (!properties().mHasOverlappingRendering) { + ALOGD("%*sScaleAlpha %.2f", level * 2, "", properties().mAlpha); } else { int flags = SkCanvas::kHasAlphaLayer_SaveFlag; if (clipToBoundsNeeded) { @@ -231,51 +128,51 @@ void DisplayList::outputViewProperties(const int level) { clipToBoundsNeeded = false; // clipping done by save layer } ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "", - (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop, - (int)(mAlpha * 255), flags); + (float) 0, (float) 0, (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop, + (int)(properties().mAlpha * 255), flags); } } if (clipToBoundsNeeded) { ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f, - (float) mRight - mLeft, (float) mBottom - mTop); + (float) properties().mRight - properties().mLeft, (float) properties().mBottom - properties().mTop); } } /* * For property operations, we pass a savecount of 0, since the operations aren't part of the * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in - * base saveCount (i.e., how RestoreToCount uses saveCount + mCount) + * base saveCount (i.e., how RestoreToCount uses saveCount + properties().mCount) */ #define PROPERTY_SAVECOUNT 0 template <class T> -void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, +void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler, const int level) { #if DEBUG_DISPLAY_LIST outputViewProperties(level); #endif - updateMatrix(); - if (mLeft != 0 || mTop != 0) { - renderer.translate(mLeft, mTop); - } - if (mStaticMatrix) { - renderer.concatMatrix(mStaticMatrix); - } else if (mAnimationMatrix) { - renderer.concatMatrix(mAnimationMatrix); - } - if (mMatrixFlags != 0) { - if (mMatrixFlags == TRANSLATION) { - renderer.translate(mTranslationX, mTranslationY); + properties().updateMatrix(); + if (properties().mLeft != 0 || properties().mTop != 0) { + renderer.translate(properties().mLeft, properties().mTop); + } + if (properties().mStaticMatrix) { + renderer.concatMatrix(properties().mStaticMatrix); + } else if (properties().mAnimationMatrix) { + renderer.concatMatrix(properties().mAnimationMatrix); + } + if (properties().mMatrixFlags != 0) { + if (properties().mMatrixFlags == TRANSLATION) { + renderer.translate(properties().mTranslationX, properties().mTranslationY); } else { - renderer.concatMatrix(*mTransformMatrix); + renderer.concatMatrix(*properties().mTransformMatrix); } } - bool clipToBoundsNeeded = mCaching ? false : mClipToBounds; - if (mAlpha < 1) { - if (mCaching) { - renderer.setOverrideLayerAlpha(mAlpha); - } else if (!mHasOverlappingRendering) { - renderer.scaleAlpha(mAlpha); + bool clipToBoundsNeeded = properties().mCaching ? false : properties().mClipToBounds; + if (properties().mAlpha < 1) { + if (properties().mCaching) { + renderer.setOverrideLayerAlpha(properties().mAlpha); + } else if (!properties().mHasOverlappingRendering) { + renderer.scaleAlpha(properties().mAlpha); } else { // TODO: should be able to store the size of a DL at record time and not // have to pass it into this call. In fact, this information might be in the @@ -287,18 +184,18 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, } SaveLayerOp* op = new (handler.allocator()) SaveLayerOp( - 0, 0, mRight - mLeft, mBottom - mTop, mAlpha * 255, saveFlags); - handler(op, PROPERTY_SAVECOUNT, mClipToBounds); + 0, 0, properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, properties().mAlpha * 255, saveFlags); + handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds); } } if (clipToBoundsNeeded) { ClipRectOp* op = new (handler.allocator()) ClipRectOp(0, 0, - mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op); - handler(op, PROPERTY_SAVECOUNT, mClipToBounds); + properties().mRight - properties().mLeft, properties().mBottom - properties().mTop, SkRegion::kIntersect_Op); + handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds); } - if (CC_UNLIKELY(mClipToOutline && !mOutline.isEmpty())) { - ClipPathOp* op = new (handler.allocator()) ClipPathOp(&mOutline, SkRegion::kIntersect_Op); - handler(op, PROPERTY_SAVECOUNT, mClipToBounds); + if (CC_UNLIKELY(properties().mClipToOutline && !properties().mOutline.isEmpty())) { + ClipPathOp* op = new (handler.allocator()) ClipPathOp(&properties().mOutline, SkRegion::kIntersect_Op); + handler(op, PROPERTY_SAVECOUNT, properties().mClipToBounds); } } @@ -308,36 +205,36 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler, * If true3dTransform is set to true, the transform applied to the input matrix will use true 4x4 * matrix computation instead of the Skia 3x3 matrix + camera hackery. */ -void DisplayList::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) { - if (mLeft != 0 || mTop != 0) { - matrix.translate(mLeft, mTop); +void RenderNode::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform) { + if (properties().mLeft != 0 || properties().mTop != 0) { + matrix.translate(properties().mLeft, properties().mTop); } - if (mStaticMatrix) { - mat4 stat(*mStaticMatrix); + if (properties().mStaticMatrix) { + mat4 stat(*properties().mStaticMatrix); matrix.multiply(stat); - } else if (mAnimationMatrix) { - mat4 anim(*mAnimationMatrix); + } else if (properties().mAnimationMatrix) { + mat4 anim(*properties().mAnimationMatrix); matrix.multiply(anim); } - if (mMatrixFlags != 0) { - updateMatrix(); - if (mMatrixFlags == TRANSLATION) { - matrix.translate(mTranslationX, mTranslationY, - true3dTransform ? mTranslationZ : 0.0f); + if (properties().mMatrixFlags != 0) { + properties().updateMatrix(); + if (properties().mMatrixFlags == TRANSLATION) { + matrix.translate(properties().mTranslationX, properties().mTranslationY, + true3dTransform ? properties().mTranslationZ : 0.0f); } else { if (!true3dTransform) { - matrix.multiply(*mTransformMatrix); + matrix.multiply(*properties().mTransformMatrix); } else { mat4 true3dMat; true3dMat.loadTranslate( - mPivotX + mTranslationX, - mPivotY + mTranslationY, - mTranslationZ); - true3dMat.rotate(mRotationX, 1, 0, 0); - true3dMat.rotate(mRotationY, 0, 1, 0); - true3dMat.rotate(mRotation, 0, 0, 1); - true3dMat.scale(mScaleX, mScaleY, 1); - true3dMat.translate(-mPivotX, -mPivotY); + properties().mPivotX + properties().mTranslationX, + properties().mPivotY + properties().mTranslationY, + properties().mTranslationZ); + true3dMat.rotate(properties().mRotationX, 1, 0, 0); + true3dMat.rotate(properties().mRotationY, 0, 1, 0); + true3dMat.rotate(properties().mRotation, 0, 0, 1); + true3dMat.scale(properties().mScaleX, properties().mScaleY, 1); + true3dMat.translate(-properties().mPivotX, -properties().mPivotY); matrix.multiply(true3dMat); } @@ -353,7 +250,7 @@ void DisplayList::applyViewPropertyTransforms(mat4& matrix, bool true3dTransform * Each DisplayList that serves as a 3d root builds its list of composited children, * which are flagged to not draw in the standard draw loop. */ -void DisplayList::computeOrdering() { +void RenderNode::computeOrdering() { ATRACE_CALL(); mProjectedNodes.clear(); @@ -367,7 +264,7 @@ void DisplayList::computeOrdering() { } } -void DisplayList::computeOrderingImpl( +void RenderNode::computeOrderingImpl( DrawDisplayListOp* opState, Vector<DrawDisplayListOp*>* compositedChildrenOfProjectionSurface, const mat4* transformFromProjectionSurface) { @@ -379,7 +276,7 @@ void DisplayList::computeOrderingImpl( Matrix4 localTransformFromProjectionSurface(*transformFromProjectionSurface); localTransformFromProjectionSurface.multiply(opState->mTransformFromParent); - if (mProjectBackwards) { + if (properties().mProjectBackwards) { // composited projectee, flag for out of order draw, save matrix, and store in proj surface opState->mSkipInOrderDraw = true; opState->mTransformFromCompositingAncestor.load(localTransformFromProjectionSurface); @@ -394,11 +291,11 @@ void DisplayList::computeOrderingImpl( bool haveAppliedPropertiesToProjection = false; for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; - DisplayList* child = childOp->mDisplayList; + RenderNode* child = childOp->mDisplayList; Vector<DrawDisplayListOp*>* projectionChildren = NULL; const mat4* projectionTransform = NULL; - if (isProjectionReceiver && !child->mProjectBackwards) { + if (isProjectionReceiver && !child->properties().mProjectBackwards) { // if receiving projections, collect projecting descendent // Note that if a direct descendent is projecting backwards, we pass it's @@ -434,7 +331,7 @@ private: const int mLevel; }; -void DisplayList::defer(DeferStateStruct& deferStruct, const int level) { +void RenderNode::defer(DeferStateStruct& deferStruct, const int level) { DeferOperationHandler handler(deferStruct, level); iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level); } @@ -445,7 +342,7 @@ public: : mReplayStruct(replayStruct), mLevel(level) {} inline void operator()(DisplayListOp* operation, int saveCount, bool clipToBounds) { #if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS - mReplayStruct.mRenderer.eventMark(operation->name()); + properties().mReplayStruct.mRenderer.eventMark(operation->name()); #endif operation->replay(mReplayStruct, saveCount, mLevel, clipToBounds); } @@ -456,7 +353,7 @@ private: const int mLevel; }; -void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { +void RenderNode::replay(ReplayStateStruct& replayStruct, const int level) { ReplayOperationHandler handler(replayStruct, level); replayStruct.mRenderer.startMark(mName.string()); @@ -467,18 +364,18 @@ void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) { replayStruct.mDrawGlStatus); } -void DisplayList::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) { +void RenderNode::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTranslatedNodes) { if (mDisplayListData == NULL || mDisplayListData->children.size() == 0) return; for (unsigned int i = 0; i < mDisplayListData->children.size(); i++) { DrawDisplayListOp* childOp = mDisplayListData->children[i]; - DisplayList* child = childOp->mDisplayList; - float childZ = child->mTranslationZ; + RenderNode* child = childOp->mDisplayList; + float childZ = child->properties().mTranslationZ; if (childZ != 0.0f) { zTranslatedNodes.add(ZDrawDisplayListOpPair(childZ, childOp)); childOp->mSkipInOrderDraw = true; - } else if (!child->mProjectBackwards) { + } else if (!child->properties().mProjectBackwards) { // regular, in order drawing DisplayList childOp->mSkipInOrderDraw = false; } @@ -491,7 +388,7 @@ void DisplayList::buildZSortedChildList(Vector<ZDrawDisplayListOpPair>& zTransla #define SHADOW_DELTA 0.1f template <class T> -void DisplayList::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, +void RenderNode::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTranslatedNodes, ChildrenSelectMode mode, OpenGLRenderer& renderer, T& handler) { const int size = zTranslatedNodes.size(); if (size == 0 @@ -503,9 +400,9 @@ void DisplayList::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTrans int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); LinearAllocator& alloc = handler.allocator(); - ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, + ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().mWidth, properties().mHeight, SkRegion::kIntersect_Op); // clip to 3d root bounds - handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); + handler(clipOp, PROPERTY_SAVECOUNT, properties().mClipToBounds); /** * Draw shadows and (potential) casters mostly in order, but allow the shadows of casters @@ -529,13 +426,13 @@ void DisplayList::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTrans while (shadowIndex < endIndex || drawIndex < endIndex) { if (shadowIndex < endIndex) { DrawDisplayListOp* casterOp = zTranslatedNodes[shadowIndex].value; - DisplayList* caster = casterOp->mDisplayList; + RenderNode* caster = casterOp->mDisplayList; const float casterZ = zTranslatedNodes[shadowIndex].key; // attempt to render the shadow if the caster about to be drawn is its caster, // OR if its caster's Z value is similar to the previous potential caster if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) { - if (caster->mCastsShadow && caster->mAlpha > 0.0f) { + if (caster->properties().mCastsShadow && caster->properties().mAlpha > 0.0f) { mat4 shadowMatrixXY(casterOp->mTransformFromParent); caster->applyViewPropertyTransforms(shadowMatrixXY); @@ -545,8 +442,9 @@ void DisplayList::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTrans DisplayListOp* shadowOp = new (alloc) DrawShadowOp( shadowMatrixXY, shadowMatrixZ, - caster->mAlpha, &(caster->mOutline), caster->mWidth, caster->mHeight); - handler(shadowOp, PROPERTY_SAVECOUNT, mClipToBounds); + caster->properties().mAlpha, &(caster->properties().mOutline), + caster->properties().mWidth, caster->properties().mHeight); + handler(shadowOp, PROPERTY_SAVECOUNT, properties().mClipToBounds); } lastCasterZ = casterZ; // must do this even if current caster not casting a shadow @@ -560,26 +458,26 @@ void DisplayList::iterate3dChildren(const Vector<ZDrawDisplayListOpPair>& zTrans int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); DrawDisplayListOp* childOp = zTranslatedNodes[drawIndex].value; - DisplayList* child = childOp->mDisplayList; + RenderNode* child = childOp->mDisplayList; renderer.concatMatrix(childOp->mTransformFromParent); childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); + handler(childOp, renderer.getSaveCount() - 1, properties().mClipToBounds); childOp->mSkipInOrderDraw = true; renderer.restoreToCount(restoreTo); drawIndex++; } - handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); + handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().mClipToBounds); } template <class T> -void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { +void RenderNode::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, const int level) { int rootRestoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); LinearAllocator& alloc = handler.allocator(); - ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, mWidth, mHeight, + ClipRectOp* clipOp = new (alloc) ClipRectOp(0, 0, properties().mWidth, properties().mHeight, SkRegion::kReplace_Op); // clip to projection surface root bounds - handler(clipOp, PROPERTY_SAVECOUNT, mClipToBounds); + handler(clipOp, PROPERTY_SAVECOUNT, properties().mClipToBounds); for (size_t i = 0; i < mProjectedNodes.size(); i++) { DrawDisplayListOp* childOp = mProjectedNodes[i]; @@ -588,11 +486,11 @@ void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, int restoreTo = renderer.save(SkCanvas::kMatrix_SaveFlag); renderer.concatMatrix(childOp->mTransformFromCompositingAncestor); childOp->mSkipInOrderDraw = false; // this is horrible, I'm so sorry everyone - handler(childOp, renderer.getSaveCount() - 1, mClipToBounds); + handler(childOp, renderer.getSaveCount() - 1, properties().mClipToBounds); childOp->mSkipInOrderDraw = true; renderer.restoreToCount(restoreTo); } - handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, mClipToBounds); + handler(new (alloc) RestoreToCountOp(rootRestoreTo), PROPERTY_SAVECOUNT, properties().mClipToBounds); } /** @@ -605,12 +503,12 @@ void DisplayList::iterateProjectedChildren(OpenGLRenderer& renderer, T& handler, * defer vs replay logic, per operation */ template <class T> -void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) { +void RenderNode::iterate(OpenGLRenderer& renderer, T& handler, const int level) { if (CC_UNLIKELY(mDestroyed)) { // temporary debug logging - ALOGW("Error: %s is drawing after destruction", getName()); + ALOGW("Error: %s is drawing after destruction", mName.string()); CRASH(); } - if (mDisplayListData->isEmpty() || mAlpha <= 0) { + if (mDisplayListData->isEmpty() || properties().mAlpha <= 0) { DISPLAY_LIST_LOGD("%*sEmpty display list (%p, %s)", level * 2, "", this, mName.string()); return; } @@ -625,14 +523,14 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) LinearAllocator& alloc = handler.allocator(); int restoreTo = renderer.getSaveCount(); handler(new (alloc) SaveOp(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag), - PROPERTY_SAVECOUNT, mClipToBounds); + PROPERTY_SAVECOUNT, properties().mClipToBounds); DISPLAY_LIST_LOGD("%*sSave %d %d", (level + 1) * 2, "", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag, restoreTo); setViewProperties<T>(renderer, handler, level + 1); - bool quickRejected = mClipToBounds && renderer.quickRejectConservative(0, 0, mWidth, mHeight); + bool quickRejected = properties().mClipToBounds && renderer.quickRejectConservative(0, 0, properties().mWidth, properties().mHeight); if (!quickRejected) { Vector<ZDrawDisplayListOpPair> zTranslatedNodes; buildZSortedChildList(zTranslatedNodes); @@ -651,7 +549,7 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) #endif logBuffer.writeCommand(level, op->name()); - handler(op, saveCountOffset, mClipToBounds); + handler(op, saveCountOffset, properties().mClipToBounds); if (CC_UNLIKELY(i == projectionReceiveIndex && mProjectedNodes.size() > 0)) { iterateProjectedChildren(renderer, handler, level); @@ -664,7 +562,7 @@ void DisplayList::iterate(OpenGLRenderer& renderer, T& handler, const int level) DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo); handler(new (alloc) RestoreToCountOp(restoreTo), - PROPERTY_SAVECOUNT, mClipToBounds); + PROPERTY_SAVECOUNT, properties().mClipToBounds); renderer.setOverrideLayerAlpha(1.0f); } diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h index 189b544a..b80c118 100644 --- a/libs/hwui/DisplayList.h +++ b/libs/hwui/DisplayList.h @@ -40,12 +40,7 @@ #include "Debug.h" #include "Matrix.h" #include "DeferredDisplayList.h" - -#define TRANSLATION 0x0001 -#define ROTATION 0x0002 -#define ROTATION_3D 0x0004 -#define SCALE 0x0008 -#define PIVOT 0x0010 +#include "RenderProperties.h" class SkBitmap; class SkPaint; @@ -160,17 +155,17 @@ private: * recorded stream of canvas operations is refreshed. The DisplayList (and its properties) stay * attached. */ -class DisplayList { +class RenderNode { public: - ANDROID_API DisplayList(); - ANDROID_API ~DisplayList(); + ANDROID_API RenderNode(); + ANDROID_API ~RenderNode(); // See flags defined in DisplayList.java enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 }; - ANDROID_API static void destroyDisplayListDeferred(DisplayList* displayList); + ANDROID_API static void destroyDisplayListDeferred(RenderNode* displayList); ANDROID_API static void outputLogBuffer(int fd); ANDROID_API void setData(DisplayListData* newData); @@ -196,355 +191,20 @@ public: } } - const char* getName() const { - return mName.string(); - } - - void setClipToBounds(bool clipToBounds) { - mClipToBounds = clipToBounds; - } - - void setIsolatedZVolume(bool shouldIsolate) { - mIsolatedZVolume = shouldIsolate; - } - - void setCastsShadow(bool castsShadow) { - mCastsShadow = castsShadow; - } - - void setUsesGlobalCamera(bool usesGlobalCamera) { - mUsesGlobalCamera = usesGlobalCamera; - } - - void setProjectBackwards(bool shouldProject) { - mProjectBackwards = shouldProject; - } - - void setProjectionReceiver(bool shouldRecieve) { - mProjectionReceiver = shouldRecieve; + RenderProperties& properties() { + return mProperties; } bool isProjectionReceiver() { - return mProjectionReceiver; - } - - void setOutline(const SkPath* outline) { - if (!outline) { - mOutline.reset(); - } else { - mOutline = *outline; - } - } - - void setClipToOutline(bool clipToOutline) { - mClipToOutline = clipToOutline; - } - - void setStaticMatrix(SkMatrix* matrix) { - delete mStaticMatrix; - mStaticMatrix = new SkMatrix(*matrix); - } - - // Can return NULL - SkMatrix* getStaticMatrix() { - return mStaticMatrix; - } - - void setAnimationMatrix(SkMatrix* matrix) { - delete mAnimationMatrix; - if (matrix) { - mAnimationMatrix = new SkMatrix(*matrix); - } else { - mAnimationMatrix = NULL; - } - } - - void setAlpha(float alpha) { - alpha = fminf(1.0f, fmaxf(0.0f, alpha)); - if (alpha != mAlpha) { - mAlpha = alpha; - } - } - - float getAlpha() const { - return mAlpha; - } - - void setHasOverlappingRendering(bool hasOverlappingRendering) { - mHasOverlappingRendering = hasOverlappingRendering; - } - - bool hasOverlappingRendering() const { - return mHasOverlappingRendering; - } - - void setTranslationX(float translationX) { - if (translationX != mTranslationX) { - mTranslationX = translationX; - onTranslationUpdate(); - } - } - - float getTranslationX() const { - return mTranslationX; - } - - void setTranslationY(float translationY) { - if (translationY != mTranslationY) { - mTranslationY = translationY; - onTranslationUpdate(); - } - } - - float getTranslationY() const { - return mTranslationY; - } - - void setTranslationZ(float translationZ) { - if (translationZ != mTranslationZ) { - mTranslationZ = translationZ; - onTranslationUpdate(); - } - } - - float getTranslationZ() const { - return mTranslationZ; - } - - void setRotation(float rotation) { - if (rotation != mRotation) { - mRotation = rotation; - mMatrixDirty = true; - if (mRotation == 0.0f) { - mMatrixFlags &= ~ROTATION; - } else { - mMatrixFlags |= ROTATION; - } - } - } - - float getRotation() const { - return mRotation; - } - - void setRotationX(float rotationX) { - if (rotationX != mRotationX) { - mRotationX = rotationX; - mMatrixDirty = true; - if (mRotationX == 0.0f && mRotationY == 0.0f) { - mMatrixFlags &= ~ROTATION_3D; - } else { - mMatrixFlags |= ROTATION_3D; - } - } - } - - float getRotationX() const { - return mRotationX; - } - - void setRotationY(float rotationY) { - if (rotationY != mRotationY) { - mRotationY = rotationY; - mMatrixDirty = true; - if (mRotationX == 0.0f && mRotationY == 0.0f) { - mMatrixFlags &= ~ROTATION_3D; - } else { - mMatrixFlags |= ROTATION_3D; - } - } - } - - float getRotationY() const { - return mRotationY; - } - - void setScaleX(float scaleX) { - if (scaleX != mScaleX) { - mScaleX = scaleX; - mMatrixDirty = true; - if (mScaleX == 1.0f && mScaleY == 1.0f) { - mMatrixFlags &= ~SCALE; - } else { - mMatrixFlags |= SCALE; - } - } - } - - float getScaleX() const { - return mScaleX; - } - - void setScaleY(float scaleY) { - if (scaleY != mScaleY) { - mScaleY = scaleY; - mMatrixDirty = true; - if (mScaleX == 1.0f && mScaleY == 1.0f) { - mMatrixFlags &= ~SCALE; - } else { - mMatrixFlags |= SCALE; - } - } - } - - float getScaleY() const { - return mScaleY; - } - - void setPivotX(float pivotX) { - mPivotX = pivotX; - mMatrixDirty = true; - if (mPivotX == 0.0f && mPivotY == 0.0f) { - mMatrixFlags &= ~PIVOT; - } else { - mMatrixFlags |= PIVOT; - } - mPivotExplicitlySet = true; - } - - ANDROID_API float getPivotX(); - - void setPivotY(float pivotY) { - mPivotY = pivotY; - mMatrixDirty = true; - if (mPivotX == 0.0f && mPivotY == 0.0f) { - mMatrixFlags &= ~PIVOT; - } else { - mMatrixFlags |= PIVOT; - } - mPivotExplicitlySet = true; - } - - ANDROID_API float getPivotY(); - - void setCameraDistance(float distance) { - if (distance != mCameraDistance) { - mCameraDistance = distance; - mMatrixDirty = true; - if (!mTransformCamera) { - mTransformCamera = new Sk3DView(); - mTransformMatrix3D = new SkMatrix(); - } - mTransformCamera->setCameraLocation(0, 0, distance); - } - } - - float getCameraDistance() const { - return mCameraDistance; - } - - void setLeft(int left) { - if (left != mLeft) { - mLeft = left; - mWidth = mRight - mLeft; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - float getLeft() const { - return mLeft; - } - - void setTop(int top) { - if (top != mTop) { - mTop = top; - mHeight = mBottom - mTop; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - float getTop() const { - return mTop; - } - - void setRight(int right) { - if (right != mRight) { - mRight = right; - mWidth = mRight - mLeft; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - float getRight() const { - return mRight; - } - - void setBottom(int bottom) { - if (bottom != mBottom) { - mBottom = bottom; - mHeight = mBottom - mTop; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - float getBottom() const { - return mBottom; - } - - void setLeftTop(int left, int top) { - if (left != mLeft || top != mTop) { - mLeft = left; - mTop = top; - mWidth = mRight - mLeft; - mHeight = mBottom - mTop; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - void setLeftTopRightBottom(int left, int top, int right, int bottom) { - if (left != mLeft || top != mTop || right != mRight || bottom != mBottom) { - mLeft = left; - mTop = top; - mRight = right; - mBottom = bottom; - mWidth = mRight - mLeft; - mHeight = mBottom - mTop; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - void offsetLeftRight(float offset) { - if (offset != 0) { - mLeft += offset; - mRight += offset; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - void offsetTopBottom(float offset) { - if (offset != 0) { - mTop += offset; - mBottom += offset; - if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { - mMatrixDirty = true; - } - } - } - - void setCaching(bool caching) { - mCaching = caching; + return properties().isProjectionReceiver(); } int getWidth() { - return mWidth; + return properties().getWidth(); } int getHeight() { - return mHeight; + return properties().getHeight(); } private: @@ -562,15 +222,6 @@ private: kPositiveZChildren }; - void onTranslationUpdate() { - mMatrixDirty = true; - if (mTranslationX == 0.0f && mTranslationY == 0.0f && mTranslationZ == 0.0f) { - mMatrixFlags &= ~TRANSLATION; - } else { - mMatrixFlags |= TRANSLATION; - } - } - void outputViewProperties(const int level); void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false); @@ -594,8 +245,6 @@ private: template <class T> inline void iterate(OpenGLRenderer& renderer, T& handler, const int level); - void updateMatrix(); - class TextContainer { public: size_t length() const { @@ -610,48 +259,11 @@ private: const char* mText; }; - DisplayListData* mDisplayListData; - String8 mName; bool mDestroyed; // used for debugging crash, TODO: remove once invalid state crash fixed - // Rendering properties - bool mClipToBounds; - bool mIsolatedZVolume; - bool mProjectBackwards; - bool mProjectionReceiver; - SkPath mOutline; - bool mClipToOutline; - bool mCastsShadow; - bool mUsesGlobalCamera; // TODO: respect value when rendering - float mAlpha; - bool mHasOverlappingRendering; - float mTranslationX, mTranslationY, mTranslationZ; - float mRotation, mRotationX, mRotationY; - float mScaleX, mScaleY; - float mPivotX, mPivotY; - float mCameraDistance; - int mLeft, mTop, mRight, mBottom; - int mWidth, mHeight; - int mPrevWidth, mPrevHeight; - bool mPivotExplicitlySet; - bool mMatrixDirty; - bool mMatrixIsIdentity; - - /** - * Stores the total transformation of the DisplayList based upon its scalar - * translate/rotate/scale properties. - * - * In the common translation-only case, the matrix isn't allocated and the mTranslation - * properties are used directly. - */ - Matrix4* mTransformMatrix; - uint32_t mMatrixFlags; - Sk3DView* mTransformCamera; - SkMatrix* mTransformMatrix3D; - SkMatrix* mStaticMatrix; - SkMatrix* mAnimationMatrix; - bool mCaching; + RenderProperties mProperties; + DisplayListData* mDisplayListData; /** * Draw time state - these properties are only set and used during rendering diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index 6ce8317..549b786 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -1488,9 +1488,9 @@ private: }; class DrawDisplayListOp : public DrawBoundedOp { - friend class DisplayList; // grant DisplayList access to info of child + friend class RenderNode; // grant DisplayList access to info of child public: - DrawDisplayListOp(DisplayList* displayList, int flags, const mat4& transformFromParent) + DrawDisplayListOp(RenderNode* displayList, int flags, const mat4& transformFromParent) : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0), mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {} @@ -1522,7 +1522,7 @@ public: virtual const char* name() { return "DrawDisplayList"; } private: - DisplayList* mDisplayList; + RenderNode* mDisplayList; const int mFlags; /////////////////////////// diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 3b1d567..e69e08e 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -179,7 +179,7 @@ bool DisplayListRenderer::clipRegion(const SkRegion* region, SkRegion::Op op) { return StatefulBaseRenderer::clipRegion(region, op); } -status_t DisplayListRenderer::drawDisplayList(DisplayList* displayList, +status_t DisplayListRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t flags) { // dirty is an out parameter and should not be recorded, // it matters only when replaying the display list diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 1fb72ce..65498a5 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -156,7 +156,7 @@ public: // Canvas draw operations - special // ---------------------------------------------------------------------------- virtual status_t drawLayer(Layer* layer, float x, float y); - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, + virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags); // TODO: rename for consistency @@ -309,7 +309,7 @@ private: int mRestoreSaveCount; - friend class DisplayList; + friend class RenderNode; }; // class DisplayListRenderer diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index 8992a13..52176d4 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -194,7 +194,7 @@ void Layer::defer() { deferredList = new DeferredDisplayList(dirtyRect); DeferStateStruct deferredState(*deferredList, *renderer, - DisplayList::kReplayFlag_ClipChildren); + RenderNode::kReplayFlag_ClipChildren); renderer->initViewport(width, height); renderer->setupFrameState(dirtyRect.left, dirtyRect.top, @@ -238,7 +238,7 @@ void Layer::render() { renderer->prepareDirty(dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom, !isBlend()); - renderer->drawDisplayList(displayList, dirtyRect, DisplayList::kReplayFlag_ClipChildren); + renderer->drawDisplayList(displayList, dirtyRect, RenderNode::kReplayFlag_ClipChildren); renderer->finish(); renderer = NULL; diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index f6538f2..d8440ea 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -43,7 +43,7 @@ namespace uirenderer { // Forward declarations class Caches; class OpenGLRenderer; -class DisplayList; +class RenderNode; class DeferredDisplayList; class DeferStateStruct; @@ -84,7 +84,7 @@ public: regionRect.translate(layer.left, layer.top); } - void updateDeferred(OpenGLRenderer* renderer, DisplayList* displayList, + void updateDeferred(OpenGLRenderer* renderer, RenderNode* displayList, int left, int top, int right, int bottom) { this->renderer = renderer; this->displayList = displayList; @@ -294,7 +294,7 @@ public: */ bool deferredUpdateScheduled; OpenGLRenderer* renderer; - DisplayList* displayList; + RenderNode* displayList; Rect dirtyRect; bool debugDrawUpdate; bool hasDrawnSinceUpdate; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index 879b4c7..1475953 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1912,7 +1912,7 @@ void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) { // Drawing /////////////////////////////////////////////////////////////////////////////// -status_t OpenGLRenderer::drawDisplayList(DisplayList* displayList, Rect& dirty, +status_t OpenGLRenderer::drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags) { status_t status; // All the usual checks and setup operations (quickReject, setupDraw, etc.) diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 76dd014..94abfa7 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -54,7 +54,7 @@ namespace android { namespace uirenderer { class DeferredDisplayState; -class DisplayList; +class RenderNode; class TextSetupFunctor; class VertexBuffer; class SkiaShader; @@ -165,7 +165,7 @@ public: int saveLayerDeferred(float left, float top, float right, float bottom, const SkPaint* paint, int flags); - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags = 1); + virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1); virtual status_t drawLayer(Layer* layer, float x, float y); virtual status_t drawBitmap(const SkBitmap* bitmap, float left, float top, const SkPaint* paint); diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp new file mode 100644 index 0000000..714fd1b --- /dev/null +++ b/libs/hwui/RenderProperties.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RenderProperties.h" + +#include <SkMatrix.h> + +#include "Matrix.h" + +namespace android { +namespace uirenderer { + +RenderProperties::RenderProperties() + : mClipToBounds(true) + , mProjectBackwards(false) + , mProjectionReceiver(false) + , mClipToOutline(false) + , mCastsShadow(false) + , mUsesGlobalCamera(false) // TODO: respect value when rendering + , mAlpha(1) + , mHasOverlappingRendering(true) + , mTranslationX(0), mTranslationY(0), mTranslationZ(0) + , mRotation(0), mRotationX(0), mRotationY(0) + , mScaleX(1), mScaleY(1) + , mPivotX(0), mPivotY(0) + , mCameraDistance(0) + , mLeft(0), mTop(0), mRight(0), mBottom(0) + , mWidth(0), mHeight(0) + , mPrevWidth(-1), mPrevHeight(-1) + , mPivotExplicitlySet(false) + , mMatrixDirty(false) + , mMatrixIsIdentity(true) + , mTransformMatrix(NULL) + , mMatrixFlags(0) + , mTransformCamera(NULL) + , mTransformMatrix3D(NULL) + , mStaticMatrix(NULL) + , mAnimationMatrix(NULL) + , mCaching(false) { + mOutline.rewind(); +} + +RenderProperties::~RenderProperties() { + delete mTransformMatrix; + delete mTransformCamera; + delete mTransformMatrix3D; + delete mStaticMatrix; + delete mAnimationMatrix; +} + +float RenderProperties::getPivotX() { + updateMatrix(); + return mPivotX; +} + +float RenderProperties::getPivotY() { + updateMatrix(); + return mPivotY; +} + +void RenderProperties::updateMatrix() { + if (mMatrixDirty) { + // NOTE: mTransformMatrix won't be up to date if a DisplayList goes from a complex transform + // to a pure translate. This is safe because the matrix isn't read in pure translate cases. + if (mMatrixFlags && mMatrixFlags != TRANSLATION) { + if (!mTransformMatrix) { + // only allocate a matrix if we have a complex transform + mTransformMatrix = new Matrix4(); + } + if (!mPivotExplicitlySet) { + if (mWidth != mPrevWidth || mHeight != mPrevHeight) { + mPrevWidth = mWidth; + mPrevHeight = mHeight; + mPivotX = mPrevWidth / 2.0f; + mPivotY = mPrevHeight / 2.0f; + } + } + + if ((mMatrixFlags & ROTATION_3D) == 0) { + mTransformMatrix->loadTranslate( + mPivotX + mTranslationX, + mPivotY + mTranslationY, + 0); + mTransformMatrix->rotate(mRotation, 0, 0, 1); + mTransformMatrix->scale(mScaleX, mScaleY, 1); + mTransformMatrix->translate(-mPivotX, -mPivotY); + } else { + if (!mTransformCamera) { + mTransformCamera = new Sk3DView(); + mTransformMatrix3D = new SkMatrix(); + } + SkMatrix transformMatrix; + transformMatrix.reset(); + mTransformCamera->save(); + transformMatrix.preScale(mScaleX, mScaleY, mPivotX, mPivotY); + mTransformCamera->rotateX(mRotationX); + mTransformCamera->rotateY(mRotationY); + mTransformCamera->rotateZ(-mRotation); + mTransformCamera->getMatrix(mTransformMatrix3D); + mTransformMatrix3D->preTranslate(-mPivotX, -mPivotY); + mTransformMatrix3D->postTranslate(mPivotX + mTranslationX, + mPivotY + mTranslationY); + transformMatrix.postConcat(*mTransformMatrix3D); + mTransformCamera->restore(); + + mTransformMatrix->load(transformMatrix); + } + } + mMatrixDirty = false; + } +} + +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h new file mode 100644 index 0000000..a5ce4a6 --- /dev/null +++ b/libs/hwui/RenderProperties.h @@ -0,0 +1,449 @@ +/* + * 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. + */ +#ifndef RENDERNODEPROPERTIES_H_ +#define RENDERNODEPROPERTIES_H_ + +#include <stddef.h> +#include <cutils/compiler.h> +#include <androidfw/ResourceTypes.h> + +#include <SkCamera.h> +#include <SkMatrix.h> +#include <SkPath.h> + +#define TRANSLATION 0x0001 +#define ROTATION 0x0002 +#define ROTATION_3D 0x0004 +#define SCALE 0x0008 +#define PIVOT 0x0010 + +class SkBitmap; +class SkPaint; +class SkRegion; + +namespace android { +namespace uirenderer { + +class Matrix4; +class RenderNode; + +/* + * Data structure that holds the properties for a RenderNode + */ +class RenderProperties { +public: + RenderProperties(); + virtual ~RenderProperties(); + + void setClipToBounds(bool clipToBounds) { + mClipToBounds = clipToBounds; + } + + void setCastsShadow(bool castsShadow) { + mCastsShadow = castsShadow; + } + + void setUsesGlobalCamera(bool usesGlobalCamera) { + mUsesGlobalCamera = usesGlobalCamera; + } + + void setProjectBackwards(bool shouldProject) { + mProjectBackwards = shouldProject; + } + + void setProjectionReceiver(bool shouldRecieve) { + mProjectionReceiver = shouldRecieve; + } + + bool isProjectionReceiver() { + return mProjectionReceiver; + } + + void setOutline(const SkPath* outline) { + if (!outline) { + mOutline.reset(); + } else { + mOutline = *outline; + } + } + + void setClipToOutline(bool clipToOutline) { + mClipToOutline = clipToOutline; + } + + void setStaticMatrix(SkMatrix* matrix) { + delete mStaticMatrix; + mStaticMatrix = new SkMatrix(*matrix); + } + + // Can return NULL + SkMatrix* getStaticMatrix() { + return mStaticMatrix; + } + + void setAnimationMatrix(SkMatrix* matrix) { + delete mAnimationMatrix; + if (matrix) { + mAnimationMatrix = new SkMatrix(*matrix); + } else { + mAnimationMatrix = NULL; + } + } + + void setAlpha(float alpha) { + alpha = fminf(1.0f, fmaxf(0.0f, alpha)); + if (alpha != mAlpha) { + mAlpha = alpha; + } + } + + float getAlpha() const { + return mAlpha; + } + + void setHasOverlappingRendering(bool hasOverlappingRendering) { + mHasOverlappingRendering = hasOverlappingRendering; + } + + bool hasOverlappingRendering() const { + return mHasOverlappingRendering; + } + + void setTranslationX(float translationX) { + if (translationX != mTranslationX) { + mTranslationX = translationX; + onTranslationUpdate(); + } + } + + float getTranslationX() const { + return mTranslationX; + } + + void setTranslationY(float translationY) { + if (translationY != mTranslationY) { + mTranslationY = translationY; + onTranslationUpdate(); + } + } + + float getTranslationY() const { + return mTranslationY; + } + + void setTranslationZ(float translationZ) { + if (translationZ != mTranslationZ) { + mTranslationZ = translationZ; + onTranslationUpdate(); + } + } + + float getTranslationZ() const { + return mTranslationZ; + } + + void setRotation(float rotation) { + if (rotation != mRotation) { + mRotation = rotation; + mMatrixDirty = true; + if (mRotation == 0.0f) { + mMatrixFlags &= ~ROTATION; + } else { + mMatrixFlags |= ROTATION; + } + } + } + + float getRotation() const { + return mRotation; + } + + void setRotationX(float rotationX) { + if (rotationX != mRotationX) { + mRotationX = rotationX; + mMatrixDirty = true; + if (mRotationX == 0.0f && mRotationY == 0.0f) { + mMatrixFlags &= ~ROTATION_3D; + } else { + mMatrixFlags |= ROTATION_3D; + } + } + } + + float getRotationX() const { + return mRotationX; + } + + void setRotationY(float rotationY) { + if (rotationY != mRotationY) { + mRotationY = rotationY; + mMatrixDirty = true; + if (mRotationX == 0.0f && mRotationY == 0.0f) { + mMatrixFlags &= ~ROTATION_3D; + } else { + mMatrixFlags |= ROTATION_3D; + } + } + } + + float getRotationY() const { + return mRotationY; + } + + void setScaleX(float scaleX) { + if (scaleX != mScaleX) { + mScaleX = scaleX; + mMatrixDirty = true; + if (mScaleX == 1.0f && mScaleY == 1.0f) { + mMatrixFlags &= ~SCALE; + } else { + mMatrixFlags |= SCALE; + } + } + } + + float getScaleX() const { + return mScaleX; + } + + void setScaleY(float scaleY) { + if (scaleY != mScaleY) { + mScaleY = scaleY; + mMatrixDirty = true; + if (mScaleX == 1.0f && mScaleY == 1.0f) { + mMatrixFlags &= ~SCALE; + } else { + mMatrixFlags |= SCALE; + } + } + } + + float getScaleY() const { + return mScaleY; + } + + void setPivotX(float pivotX) { + mPivotX = pivotX; + mMatrixDirty = true; + if (mPivotX == 0.0f && mPivotY == 0.0f) { + mMatrixFlags &= ~PIVOT; + } else { + mMatrixFlags |= PIVOT; + } + mPivotExplicitlySet = true; + } + + ANDROID_API float getPivotX(); + + void setPivotY(float pivotY) { + mPivotY = pivotY; + mMatrixDirty = true; + if (mPivotX == 0.0f && mPivotY == 0.0f) { + mMatrixFlags &= ~PIVOT; + } else { + mMatrixFlags |= PIVOT; + } + mPivotExplicitlySet = true; + } + + ANDROID_API float getPivotY(); + + void setCameraDistance(float distance) { + if (distance != mCameraDistance) { + mCameraDistance = distance; + mMatrixDirty = true; + if (!mTransformCamera) { + mTransformCamera = new Sk3DView(); + mTransformMatrix3D = new SkMatrix(); + } + mTransformCamera->setCameraLocation(0, 0, distance); + } + } + + float getCameraDistance() const { + return mCameraDistance; + } + + void setLeft(int left) { + if (left != mLeft) { + mLeft = left; + mWidth = mRight - mLeft; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + float getLeft() const { + return mLeft; + } + + void setTop(int top) { + if (top != mTop) { + mTop = top; + mHeight = mBottom - mTop; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + float getTop() const { + return mTop; + } + + void setRight(int right) { + if (right != mRight) { + mRight = right; + mWidth = mRight - mLeft; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + float getRight() const { + return mRight; + } + + void setBottom(int bottom) { + if (bottom != mBottom) { + mBottom = bottom; + mHeight = mBottom - mTop; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + float getBottom() const { + return mBottom; + } + + void setLeftTop(int left, int top) { + if (left != mLeft || top != mTop) { + mLeft = left; + mTop = top; + mWidth = mRight - mLeft; + mHeight = mBottom - mTop; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + void setLeftTopRightBottom(int left, int top, int right, int bottom) { + if (left != mLeft || top != mTop || right != mRight || bottom != mBottom) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + mWidth = mRight - mLeft; + mHeight = mBottom - mTop; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + void offsetLeftRight(float offset) { + if (offset != 0) { + mLeft += offset; + mRight += offset; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + void offsetTopBottom(float offset) { + if (offset != 0) { + mTop += offset; + mBottom += offset; + if (mMatrixFlags > TRANSLATION && !mPivotExplicitlySet) { + mMatrixDirty = true; + } + } + } + + void setCaching(bool caching) { + mCaching = caching; + } + + int getWidth() { + return mWidth; + } + + int getHeight() { + return mHeight; + } + +private: + void onTranslationUpdate() { + mMatrixDirty = true; + if (mTranslationX == 0.0f && mTranslationY == 0.0f && mTranslationZ == 0.0f) { + mMatrixFlags &= ~TRANSLATION; + } else { + mMatrixFlags |= TRANSLATION; + } + } + + void updateMatrix(); + + // Rendering properties + bool mClipToBounds; + bool mProjectBackwards; + bool mProjectionReceiver; + SkPath mOutline; + bool mClipToOutline; + bool mCastsShadow; + bool mUsesGlobalCamera; // TODO: respect value when rendering + float mAlpha; + bool mHasOverlappingRendering; + float mTranslationX, mTranslationY, mTranslationZ; + float mRotation, mRotationX, mRotationY; + float mScaleX, mScaleY; + float mPivotX, mPivotY; + float mCameraDistance; + int mLeft, mTop, mRight, mBottom; + int mWidth, mHeight; + int mPrevWidth, mPrevHeight; + bool mPivotExplicitlySet; + bool mMatrixDirty; + bool mMatrixIsIdentity; + + /** + * Stores the total transformation of the DisplayList based upon its scalar + * translate/rotate/scale properties. + * + * In the common translation-only case, the matrix isn't allocated and the mTranslation + * properties are used directly. + */ + Matrix4* mTransformMatrix; + uint32_t mMatrixFlags; + Sk3DView* mTransformCamera; + SkMatrix* mTransformMatrix3D; + SkMatrix* mStaticMatrix; + SkMatrix* mAnimationMatrix; + bool mCaching; + + friend class RenderNode; +}; + +} /* namespace uirenderer */ +} /* namespace android */ + +#endif /* RENDERNODEPROPERTIES_H_ */ diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index 4754bad..efcea5f 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -31,7 +31,7 @@ struct Res_png_9patch; namespace uirenderer { -class DisplayList; +class RenderNode; class Layer; class Matrix4; class SkiaColorFilter; @@ -232,7 +232,7 @@ public: // Canvas draw operations - special // ---------------------------------------------------------------------------- virtual status_t drawLayer(Layer* layer, float x, float y) = 0; - virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, + virtual status_t drawDisplayList(RenderNode* displayList, Rect& dirty, int32_t replayFlags) = 0; // TODO: rename for consistency diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index ce66d8f..5ed9f1d 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -373,7 +373,7 @@ void CanvasContext::setup(int width, int height) { mCanvas->setViewport(width, height); } -void CanvasContext::setDisplayListData(DisplayList* displayList, DisplayListData* newData) { +void CanvasContext::setDisplayListData(RenderNode* displayList, DisplayListData* newData) { displayList->setData(newData); } @@ -388,7 +388,7 @@ void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* lay } } -void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) { +void CanvasContext::drawDisplayList(RenderNode* displayList, Rect* dirty) { LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE, "drawDisplayList called on a context with no canvas or surface!"); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 649ffb6..e3fdf97 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -31,7 +31,7 @@ namespace android { namespace uirenderer { class DeferredLayerUpdater; -class DisplayList; +class RenderNode; class DisplayListData; class OpenGLRenderer; class Rect; @@ -63,9 +63,9 @@ public: bool initialize(EGLNativeWindowType window); void updateSurface(EGLNativeWindowType window); void setup(int width, int height); - void setDisplayListData(DisplayList* displayList, DisplayListData* newData); + void setDisplayListData(RenderNode* displayList, DisplayListData* newData); void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters); - void drawDisplayList(DisplayList* displayList, Rect* dirty); + void drawDisplayList(RenderNode* displayList, Rect* dirty); void destroyCanvas(); bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap); diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 200c21f..93360fc 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -117,13 +117,13 @@ void RenderProxy::setup(int width, int height) { post(task); } -CREATE_BRIDGE3(setDisplayListData, CanvasContext* context, DisplayList* displayList, +CREATE_BRIDGE3(setDisplayListData, CanvasContext* context, RenderNode* displayList, DisplayListData* newData) { args->context->setDisplayListData(args->displayList, args->newData); return NULL; } -void RenderProxy::setDisplayListData(DisplayList* displayList, DisplayListData* newData) { +void RenderProxy::setDisplayListData(RenderNode* displayList, DisplayListData* newData) { SETUP_TASK(setDisplayListData); args->context = mContext; args->displayList = displayList; @@ -131,7 +131,7 @@ void RenderProxy::setDisplayListData(DisplayList* displayList, DisplayListData* post(task); } -CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList, +CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, RenderNode* displayList, Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) { Rect* dirty = &args->dirty; if (dirty->bottom == -1 && dirty->left == -1 && @@ -143,7 +143,7 @@ CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList return NULL; } -void RenderProxy::drawDisplayList(DisplayList* displayList, +void RenderProxy::drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom) { SETUP_TASK(drawDisplayList); args->context = mContext; diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 83a8a8f..73e9805 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -32,7 +32,7 @@ namespace android { namespace uirenderer { class DeferredLayerUpdater; -class DisplayList; +class RenderNode; class DisplayListData; class Layer; class Rect; @@ -60,8 +60,8 @@ public: ANDROID_API bool initialize(EGLNativeWindowType window); ANDROID_API void updateSurface(EGLNativeWindowType window); ANDROID_API void setup(int width, int height); - ANDROID_API void setDisplayListData(DisplayList* displayList, DisplayListData* newData); - ANDROID_API void drawDisplayList(DisplayList* displayList, + ANDROID_API void setDisplayListData(RenderNode* displayList, DisplayListData* newData); + ANDROID_API void drawDisplayList(RenderNode* displayList, int dirtyLeft, int dirtyTop, int dirtyRight, int dirtyBottom); ANDROID_API void destroyCanvas(); diff --git a/media/java/android/media/Rating.java b/media/java/android/media/Rating.java index b94db18..f4fbe2c 100644 --- a/media/java/android/media/Rating.java +++ b/media/java/android/media/Rating.java @@ -29,8 +29,13 @@ import android.util.Log; * through one of the factory methods. */ public final class Rating implements Parcelable { - private final static String TAG = "Rating"; + /** + * Indicates a rating style is not supported. A Rating will never have this + * type, but can be used by other classes to indicate they do not support + * Rating. + */ + public final static int RATING_NONE = 0; /** * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to diff --git a/media/java/android/media/session/IMediaController.aidl b/media/java/android/media/session/IMediaController.aidl index 8ca0e45..d34e973 100644 --- a/media/java/android/media/session/IMediaController.aidl +++ b/media/java/android/media/session/IMediaController.aidl @@ -16,9 +16,12 @@ package android.media.session; import android.content.Intent; +import android.media.Rating; import android.media.session.IMediaControllerCallback; +import android.media.session.MediaMetadata; +import android.media.session.PlaybackState; import android.os.Bundle; -import android.os.IBinder; +import android.os.ResultReceiver; import android.view.KeyEvent; /** @@ -26,9 +29,23 @@ import android.view.KeyEvent; * @hide */ interface IMediaController { - void sendCommand(String command, in Bundle extras); + void sendCommand(String command, in Bundle extras, in ResultReceiver cb); void sendMediaButton(in KeyEvent mediaButton); void registerCallbackListener(in IMediaControllerCallback cb); void unregisterCallbackListener(in IMediaControllerCallback cb); - int getPlaybackState(); + boolean isTransportControlEnabled(); + + // These commands are for the TransportController + void play(); + void pause(); + void stop(); + void next(); + void previous(); + void fastForward(); + void rewind(); + void seekTo(long pos); + void rate(in Rating rating); + MediaMetadata getMetadata(); + PlaybackState getPlaybackState(); + int getRatingType(); }
\ No newline at end of file diff --git a/media/java/android/media/session/IMediaControllerCallback.aidl b/media/java/android/media/session/IMediaControllerCallback.aidl index 3aa0ee4..3651f1b 100644 --- a/media/java/android/media/session/IMediaControllerCallback.aidl +++ b/media/java/android/media/session/IMediaControllerCallback.aidl @@ -15,6 +15,8 @@ package android.media.session; +import android.media.session.MediaMetadata; +import android.media.session.PlaybackState; import android.os.Bundle; /** @@ -22,7 +24,9 @@ import android.os.Bundle; */ oneway interface IMediaControllerCallback { void onEvent(String event, in Bundle extras); - void onMetadataUpdate(in Bundle metadata); - void onPlaybackUpdate(int newState); void onRouteChanged(in Bundle route); + + // These callbacks are for the TransportController + void onPlaybackStateChanged(in PlaybackState state); + void onMetadataChanged(in MediaMetadata metadata); }
\ No newline at end of file diff --git a/media/java/android/media/session/IMediaSession.aidl b/media/java/android/media/session/IMediaSession.aidl index 19f7092..aed7641 100644 --- a/media/java/android/media/session/IMediaSession.aidl +++ b/media/java/android/media/session/IMediaSession.aidl @@ -16,6 +16,8 @@ package android.media.session; import android.media.session.IMediaController; +import android.media.session.MediaMetadata; +import android.media.session.PlaybackState; import android.os.Bundle; /** @@ -23,11 +25,17 @@ import android.os.Bundle; * @hide */ interface IMediaSession { - void sendEvent(in Bundle data); - IMediaController getMediaSessionToken(); - void setPlaybackState(int state); - void setMetadata(in Bundle metadata); + void sendEvent(String event, in Bundle data); + IMediaController getMediaController(); + void setTransportPerformerEnabled(); void setRouteState(in Bundle routeState); void setRoute(in Bundle mediaRouteDescriptor); + List<String> getSupportedInterfaces(); + void publish(); void destroy(); + + // These commands are for the TransportPerformer + void setMetadata(in MediaMetadata metadata); + void setPlaybackState(in PlaybackState state); + void setRatingType(int type); }
\ No newline at end of file diff --git a/media/java/android/media/session/IMediaSessionCallback.aidl b/media/java/android/media/session/IMediaSessionCallback.aidl index eb5f222..7c183e0 100644 --- a/media/java/android/media/session/IMediaSessionCallback.aidl +++ b/media/java/android/media/session/IMediaSessionCallback.aidl @@ -15,15 +15,27 @@ package android.media.session; +import android.media.Rating; import android.content.Intent; import android.os.Bundle; -import android.os.IBinder; +import android.os.ResultReceiver; /** * @hide */ oneway interface IMediaSessionCallback { - void onCommand(String command, in Bundle extras); + void onCommand(String command, in Bundle extras, in ResultReceiver cb); void onMediaButton(in Intent mediaRequestIntent); void onRequestRouteChange(in Bundle route); + + // These callbacks are for the TransportPerformer + void onPlay(); + void onPause(); + void onStop(); + void onNext(); + void onPrevious(); + void onFastForward(); + void onRewind(); + void onSeekTo(long pos); + void onRate(in Rating rating); }
\ No newline at end of file diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 09de859..afd8b11 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -16,20 +16,17 @@ package android.media.session; -import android.content.Intent; -import android.media.session.IMediaController; -import android.media.session.IMediaControllerCallback; -import android.media.MediaMetadataRetriever; -import android.media.RemoteControlClient; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.ResultReceiver; import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; +import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -46,58 +43,62 @@ import java.util.ArrayList; public final class MediaController { private static final String TAG = "MediaController"; - private static final int MESSAGE_EVENT = 1; + private static final int MSG_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 static final int MSG_ROUTE = 4; private final IMediaController mSessionBinder; - private final CallbackStub mCbStub = new CallbackStub(); - private final ArrayList<Callback> mCbs = new ArrayList<Callback>(); + private final CallbackStub mCbStub = new CallbackStub(this); + private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); private final Object mLock = new Object(); private boolean mCbRegistered = false; + private TransportController mTransportController; + + private MediaController(IMediaController sessionBinder) { + mSessionBinder = sessionBinder; + } + /** - * 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 + * @hide */ - public MediaController(MediaSessionToken token) { - mSessionBinder = token.getBinder(); + public static MediaController fromBinder(IMediaController sessionBinder) { + MediaController controller = new MediaController(sessionBinder); + try { + controller.mSessionBinder.registerCallbackListener(controller.mCbStub); + if (controller.mSessionBinder.isTransportControlEnabled()) { + controller.mTransportController = new TransportController(sessionBinder); + } + } catch (RemoteException e) { + Log.wtf(TAG, "MediaController created with expired token", e); + controller = null; + } + return controller; } /** - * @hide + * Get a new MediaController for a MediaSessionToken. If successful the + * controller returned will be connected to the session that generated the + * token. + * + * @param token The session token to use + * @return A controller for the session or null */ - public MediaController(IMediaController sessionBinder) { - mSessionBinder = sessionBinder; + public static MediaController fromToken(MediaSessionToken token) { + return fromBinder(token.getBinder()); } /** - * 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. + * Get a TransportController if the session supports it. If it is not + * supported null will be returned. * - * @param command The command to send - * @param params Any parameters to include with the command + * @return A TransportController or null */ - 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); - } + public TransportController getTransportController() { + return mTransportController; } /** @@ -133,10 +134,10 @@ public final class MediaController { /** * Adds a callback to receive updates from the session. Updates will be - * posted on the specified handler. + * posted on the specified handler's thread. * * @param cb Cannot be null. - * @param handler The handler to post updates on, if null the callers thread + * @param handler The handler to post updates on. If null the callers thread * will be used */ public void addCallback(Callback cb, Handler handler) { @@ -160,6 +161,26 @@ public final class MediaController { } } + /** + * 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 + * @param cb The callback to receive the result on + */ + public void sendCommand(String command, Bundle params, ResultReceiver cb) { + if (TextUtils.isEmpty(command)) { + throw new IllegalArgumentException("command cannot be null or empty"); + } + try { + mSessionBinder.sendCommand(command, params, cb); + } catch (RemoteException e) { + Log.d(TAG, "Dead object in sendCommand.", e); + } + } + /* * @hide */ @@ -174,14 +195,13 @@ public final class MediaController { if (handler == null) { throw new IllegalArgumentException("Handler cannot be null"); } - if (mCbs.contains(cb)) { + if (getHandlerForCallbackLocked(cb) != null) { Log.w(TAG, "Callback is already added, ignoring"); return; } - cb.setHandler(handler); - mCbs.add(cb); + MessageHandler holder = new MessageHandler(handler.getLooper(), cb); + mCallbacks.add(holder); - // Only register one cb binder, track callbacks internally and notify if (!mCbRegistered) { try { mSessionBinder.registerCallbackListener(mCbStub); @@ -192,56 +212,58 @@ public final class MediaController { } } - private void removeCallbackLocked(Callback cb) { + private boolean 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); + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + MessageHandler handler = mCallbacks.get(i); + if (cb == handler.mCallback) { + mCallbacks.remove(i); + return true; } - mCbRegistered = false; } + return false; } - private void pushOnEventLocked(String event, Bundle extras) { - for (int i = mCbs.size() - 1; i >= 0; i--) { - mCbs.get(i).postEvent(event, extras); + private MessageHandler getHandlerForCallbackLocked(Callback cb) { + if (cb == null) { + throw new IllegalArgumentException("Callback cannot be null"); } - } - - private void pushOnMetadataUpdateLocked(Bundle metadata) { - for (int i = mCbs.size() - 1; i >= 0; i--) { - mCbs.get(i).postMetadataUpdate(metadata); + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + MessageHandler handler = mCallbacks.get(i); + if (cb == handler.mCallback) { + return handler; + } } + return null; } - private void pushOnPlaybackUpdateLocked(int newState) { - for (int i = mCbs.size() - 1; i >= 0; i--) { - mCbs.get(i).postPlaybackStateChange(newState); + private void postEvent(String event, Bundle extras) { + synchronized (mLock) { + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + mCallbacks.get(i).post(MSG_EVENT, event, extras); + } } } - private void pushOnRouteChangedLocked(Bundle routeDescriptor) { - for (int i = mCbs.size() - 1; i >= 0; i--) { - mCbs.get(i).postRouteChanged(routeDescriptor); + private void postRouteChanged(Bundle routeDescriptor) { + synchronized (mLock) { + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + mCallbacks.get(i).post(MSG_ROUTE, null, routeDescriptor); + } } } /** - * MediaSession callbacks will be posted on the thread that created the - * Callback object. + * Callback for receiving updates on from the session. A Callback can be + * registered using {@link #addCallback} */ 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. + * Override to handle custom events sent by the session owner without a + * specified interface. Controllers should only handle these for + * sessions they own. * * @param event */ @@ -249,119 +271,83 @@ public final class MediaController { } /** - * 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 final static class CallbackStub extends IMediaControllerCallback.Stub { + private final WeakReference<MediaController> mController; - private void postRouteChanged(final Bundle descriptor) { - Message msg = mHandler.obtainMessage(MESSAGE_ROUTE, descriptor); - mHandler.sendMessage(msg); + public CallbackStub(MediaController controller) { + mController = new WeakReference<MediaController>(controller); } - } - - private final class CallbackStub extends IMediaControllerCallback.Stub { @Override - public void onEvent(String event, Bundle extras) throws RemoteException { - synchronized (mLock) { - pushOnEventLocked(event, extras); + public void onEvent(String event, Bundle extras) { + MediaController controller = mController.get(); + if (controller != null) { + controller.postEvent(event, extras); } } @Override - public void onMetadataUpdate(Bundle metadata) throws RemoteException { - synchronized (mLock) { - pushOnMetadataUpdateLocked(metadata); + public void onRouteChanged(Bundle mediaRouteDescriptor) { + MediaController controller = mController.get(); + if (controller != null) { + controller.postRouteChanged(mediaRouteDescriptor); } } @Override - public void onPlaybackUpdate(final int newState) throws RemoteException { - synchronized (mLock) { - pushOnPlaybackUpdateLocked(newState); + public void onPlaybackStateChanged(PlaybackState state) { + MediaController controller = mController.get(); + if (controller != null) { + TransportController tc = controller.getTransportController(); + if (tc != null) { + tc.postPlaybackStateChanged(state); + } } } @Override - public void onRouteChanged(Bundle mediaRouteDescriptor) throws RemoteException { - synchronized (mLock) { - pushOnRouteChangedLocked(mediaRouteDescriptor); + public void onMetadataChanged(MediaMetadata metadata) { + MediaController controller = mController.get(); + if (controller != null) { + TransportController tc = controller.getTransportController(); + if (tc != null) { + tc.postMetadataChanged(metadata); + } } } } private final static class MessageHandler extends Handler { - private final MediaController.Callback mCb; + private final MediaController.Callback mCallback; public MessageHandler(Looper looper, MediaController.Callback cb) { - super(looper); - mCb = cb; + super(looper, null, true); + mCallback = 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); + case MSG_EVENT: + mCallback.onEvent((String) msg.obj, msg.getData()); break; - case MESSAGE_ROUTE: - mCb.onRouteChanged((Bundle) msg.obj); + case MSG_ROUTE: + mCallback.onRouteChanged(msg.getData()); } } + + public void post(int what, Object obj, Bundle data) { + obtainMessage(what, obj).sendToTarget(); + } } } diff --git a/media/java/android/media/session/MediaMetadata.aidl b/media/java/android/media/session/MediaMetadata.aidl new file mode 100644 index 0000000..4431d9d --- /dev/null +++ b/media/java/android/media/session/MediaMetadata.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.session; + +parcelable MediaMetadata; diff --git a/media/java/android/media/session/MediaMetadata.java b/media/java/android/media/session/MediaMetadata.java new file mode 100644 index 0000000..e2330f7 --- /dev/null +++ b/media/java/android/media/session/MediaMetadata.java @@ -0,0 +1,404 @@ +/* + * 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.session; + +import android.graphics.Bitmap; +import android.media.Rating; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.ArrayMap; +import android.util.Log; + +/** + * Contains metadata about an item, such as the title, artist, etc. + */ +public final class MediaMetadata implements Parcelable { + private static final String TAG = "MediaMetadata"; + + /** + * The title of the media. + */ + public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE"; + + /** + * The artist of the media. + */ + public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"; + + /** + * The duration of the media in ms. A duration of 0 is the default. + */ + public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION"; + + /** + * The album title for the media. + */ + public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"; + + /** + * The author of the media. + */ + public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"; + + /** + * The writer of the media. + */ + public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER"; + + /** + * The composer of the media. + */ + public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"; + + /** + * The date the media was created or published as TODO determine format. + */ + public static final String METADATA_KEY_DATE = "android.media.metadata.DATE"; + + /** + * The year the media was created or published as a numeric String. + */ + public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR"; + + /** + * The genre of the media. + */ + public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE"; + + /** + * The track number for the media. + */ + public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"; + + /** + * The number of tracks in the media's original source. + */ + public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"; + + /** + * The disc number for the media's original source. + */ + public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"; + + /** + * The artist for the album of the media's original source. + */ + public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"; + + /** + * The artwork for the media as a {@link Bitmap}. + */ + public static final String METADATA_KEY_ART = "android.media.metadata.ART"; + + /** + * The artwork for the media as a Uri style String. + */ + public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"; + + /** + * The artwork for the album of the media's original source as a + * {@link Bitmap}. + */ + public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"; + + /** + * The artwork for the album of the media's original source as a Uri style + * String. + */ + public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"; + + /** + * The user's rating for the media. + * + * @see Rating + */ + public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"; + + /** + * The overall rating for the media. + * + * @see Rating + */ + public static final String METADATA_KEY_RATING = "android.media.metadata.RATING"; + + private static final int METADATA_TYPE_INVALID = -1; + private static final int METADATA_TYPE_LONG = 0; + private static final int METADATA_TYPE_STRING = 1; + private static final int METADATA_TYPE_BITMAP = 2; + private static final int METADATA_TYPE_RATING = 3; + private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE; + + static { + METADATA_KEYS_TYPE = new ArrayMap<String, Integer>(); + METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG); + METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG); + METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG); + METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG); + METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP); + METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP); + METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_STRING); + METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING); + METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING); + } + private final Bundle mBundle; + + private MediaMetadata(Bundle bundle) { + mBundle = new Bundle(bundle); + } + + private MediaMetadata(Parcel in) { + mBundle = in.readBundle(); + } + + /** + * Returns the value associated with the given key, or null if no mapping of + * the desired type exists for the given key or a null value is explicitly + * associated with the key. + * + * @param key The key the value is stored under + * @return a String value, or null + */ + public String getString(String key) { + return mBundle.getString(key); + } + + /** + * Returns the value associated with the given key, or 0L if no long exists + * for the given key. + * + * @param key The key the value is stored under + * @return a long value + */ + public long getLong(String key) { + return mBundle.getLong(key); + } + + /** + * Return a {@link Rating} for the given key or null if no rating exists for + * the given key. + * + * @param key The key the value is stored under + * @return A {@link Rating} or null + */ + public Rating getRating(String key) { + Rating rating = null; + try { + rating = mBundle.getParcelable(key); + } catch (Exception e) { + // ignore, value was not a bitmap + Log.d(TAG, "Failed to retrieve a key as Rating.", e); + } + return rating; + } + + /** + * Return a {@link Bitmap} for the given key or null if no bitmap exists for + * the given key. + * + * @param key The key the value is stored under + * @return A {@link Bitmap} or null + */ + public Bitmap getBitmap(String key) { + Bitmap bmp = null; + try { + bmp = mBundle.getParcelable(key); + } catch (Exception e) { + // ignore, value was not a bitmap + Log.d(TAG, "Failed to retrieve a key as Bitmap.", e); + } + return bmp; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBundle(mBundle); + } + + public static final Parcelable.Creator<MediaMetadata> CREATOR + = new Parcelable.Creator<MediaMetadata>() { + @Override + public MediaMetadata createFromParcel(Parcel in) { + return new MediaMetadata(in); + } + + @Override + public MediaMetadata[] newArray(int size) { + return new MediaMetadata[size]; + } + }; + + /** + * Use to build MediaMetadata objects. The system defined metadata keys must + * use the appropriate data type. + */ + public static final class Builder { + private final Bundle mBundle; + + /** + * Create an empty Builder. Any field that should be included in the + * {@link MediaMetadata} must be added. + */ + public Builder() { + mBundle = new Bundle(); + } + + /** + * Create a Builder using a {@link MediaMetadata} instance to set the + * initial values. All fields in the source metadata will be included in + * the new metadata. Fields can be overwritten by adding the same key. + * + * @param source + */ + public Builder(MediaMetadata source) { + mBundle = new Bundle(source.mBundle); + } + + /** + * Put a String value into the metadata. Custom keys may be used, but if + * the METADATA_KEYs defined in this class are used they may only be one + * of the following: + * <ul> + * <li>{@link #METADATA_KEY_TITLE}</li> + * <li>{@link #METADATA_KEY_ARTIST}</li> + * <li>{@link #METADATA_KEY_ALBUM}</li> + * <li>{@link #METADATA_KEY_AUTHOR}</li> + * <li>{@link #METADATA_KEY_WRITER}</li> + * <li>{@link #METADATA_KEY_COMPOSER}</li> + * <li>{@link #METADATA_KEY_DATE}</li> + * <li>{@link #METADATA_KEY_YEAR}</li> + * <li>{@link #METADATA_KEY_GENRE}</li> + * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>li> + * <li>{@link #METADATA_KEY_ART_URI}</li>li> + * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li> + * </ul> + * + * @param key The key for referencing this value + * @param value The String value to store + * @return The Builder to allow chaining + */ + public Builder putString(String key, String value) { + if (METADATA_KEYS_TYPE.containsKey(key)) { + if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_STRING) { + throw new IllegalArgumentException("The " + key + + " key cannot be used to put a String"); + } + } + mBundle.putString(key, value); + return this; + } + + /** + * Put a long value into the metadata. Custom keys may be used, but if + * the METADATA_KEYs defined in this class are used they may only be one + * of the following: + * <ul> + * <li>{@link #METADATA_KEY_DURATION}</li> + * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li> + * <li>{@link #METADATA_KEY_NUM_TRACKS}</li> + * <li>{@link #METADATA_KEY_DISC_NUMBER}</li> + * </ul> + * + * @param key The key for referencing this value + * @param value The String value to store + * @return The Builder to allow chaining + */ + public Builder putLong(String key, long value) { + if (METADATA_KEYS_TYPE.containsKey(key)) { + if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) { + throw new IllegalArgumentException("The " + key + + " key cannot be used to put a long"); + } + } + mBundle.putLong(key, value); + return this; + } + + /** + * Put a {@link Rating} into the metadata. Custom keys may be used, but + * if the METADATA_KEYs defined in this class are used they may only be + * one of the following: + * <ul> + * <li>{@link #METADATA_KEY_RATING}</li> + * <li>{@link #METADATA_KEY_USER_RATING}</li> + * </ul> + * + * @param key The key for referencing this value + * @param value The String value to store + * @return The Builder to allow chaining + */ + public Builder putRating(String key, Rating value) { + if (METADATA_KEYS_TYPE.containsKey(key)) { + if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) { + throw new IllegalArgumentException("The " + key + + " key cannot be used to put a Rating"); + } + } + mBundle.putParcelable(key, value); + return this; + } + + /** + * Put a {@link Bitmap} into the metadata. Custom keys may be used, but + * if the METADATA_KEYs defined in this class are used they may only be + * one of the following: + * <ul> + * <li>{@link #METADATA_KEY_ART}</li> + * <li>{@link #METADATA_KEY_ALBUM_ART}</li> + * </ul> + * + * @param key The key for referencing this value + * @param value The Bitmap to store + * @return The Builder to allow chaining + */ + public Builder putBitmap(String key, Bitmap value) { + if (METADATA_KEYS_TYPE.containsKey(key)) { + if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) { + throw new IllegalArgumentException("The " + key + + " key cannot be used to put a Bitmap"); + } + } + mBundle.putParcelable(key, value); + return this; + } + + /** + * Creates a {@link MediaMetadata} instance with the specified fields. + * + * @return The new MediaMetadata instance + */ + public MediaMetadata build() { + return new MediaMetadata(mBundle); + } + } + +} diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 1f1533b..23c3035 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -17,17 +17,21 @@ package android.media.session; import android.content.Intent; +import android.media.Rating; import android.media.session.IMediaController; import android.media.session.IMediaSession; import android.media.session.IMediaSessionCallback; -import android.media.RemoteControlClient; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.ResultReceiver; +import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; +import java.lang.ref.WeakReference; import java.util.ArrayList; /** @@ -58,12 +62,13 @@ import java.util.ArrayList; 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 int MSG_MEDIA_BUTTON = 1; + private static final int MSG_COMMAND = 2; + private static final int MSG_ROUTE_CHANGE = 3; private static final String KEY_COMMAND = "command"; private static final String KEY_EXTRAS = "extras"; + private static final String KEY_CALLBACK = "callback"; private final Object mLock = new Object(); @@ -71,7 +76,14 @@ public final class MediaSession { private final IMediaSession mBinder; private final CallbackStub mCbStub; - private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); + private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>(); + // TODO route interfaces + private final ArrayMap<String, RouteInterface.Stub> mInterfaces + = new ArrayMap<String, RouteInterface.Stub>(); + + private TransportPerformer mPerformer; + + private boolean mPublished = false;; /** * @hide @@ -81,7 +93,7 @@ public final class MediaSession { mCbStub = cbStub; IMediaController controllerBinder = null; try { - controllerBinder = mBinder.getMediaSessionToken(); + controllerBinder = mBinder.getMediaController(); } catch (RemoteException e) { throw new RuntimeException("Dead object in MediaSessionController constructor: ", e); } @@ -102,34 +114,117 @@ public final class MediaSession { throw new IllegalArgumentException("Callback cannot be null"); } synchronized (mLock) { - if (mCallbacks.contains(callback)) { + if (getHandlerForCallbackLocked(callback) != null) { Log.w(TAG, "Callback is already added, ignoring"); + return; } if (handler == null) { handler = new Handler(); } MessageHandler msgHandler = new MessageHandler(handler.getLooper(), callback); - callback.setHandler(msgHandler); - mCallbacks.add(callback); + mCallbacks.add(msgHandler); } } public void removeCallback(Callback callback) { - mCallbacks.remove(callback); + synchronized (mLock) { + removeCallbackLocked(callback); + } + } + + /** + * Start using a TransportPerformer with this media session. This must be + * called before calling publish and cannot be called more than once. + * Calling this will allow MediaControllers to retrieve a + * TransportController. + * + * @see TransportController + * @return The TransportPerformer created for this session + */ + public TransportPerformer setTransportPerformerEnabled() { + if (mPerformer != null) { + throw new IllegalStateException("setTransportPerformer can only be called once."); + } + if (mPublished) { + throw new IllegalStateException("setTransportPerformer cannot be called after publish"); + } + + mPerformer = new TransportPerformer(mBinder); + try { + mBinder.setTransportPerformerEnabled(); + } catch (RemoteException e) { + Log.wtf(TAG, "Failure in setTransportPerformerEnabled.", e); + } + return mPerformer; + } + + /** + * Retrieves the TransportPerformer used by this session. If called before + * {@link #setTransportPerformerEnabled} null will be returned. + * + * @return The TransportPerformer associated with this session or null + */ + public TransportPerformer getTransportPerformer() { + return mPerformer; + } + + /** + * Call after you have finished setting up the session. This will make it + * available to listeners and begin pushing updates to MediaControllers. + * This can only be called once. + */ + public void publish() { + if (mPublished) { + throw new RuntimeException("publish() may only be called once."); + } + try { + mBinder.publish(); + } catch (RemoteException e) { + Log.wtf(TAG, "Failure in publish.", e); + } + mPublished = true; + } + + /** + * Add an interface that can be used by MediaSessions. TODO make this a + * route provider api + * + * @see RouteInterface + * @param iface The interface to add + * @hide + */ + public void addInterface(RouteInterface.Stub iface) { + if (iface == null) { + throw new IllegalArgumentException("Stub cannot be null"); + } + String name = iface.getName(); + if (TextUtils.isEmpty(name)) { + throw new IllegalArgumentException("Stub must return a valid name"); + } + if (mInterfaces.containsKey(iface)) { + throw new IllegalArgumentException("Interface is already added"); + } + synchronized (mLock) { + mInterfaces.put(iface.getName(), iface); + } } /** - * Publish the current playback state to the system and any controllers. - * Valid values are defined in {@link RemoteControlClient}. TODO move play - * states somewhere else. + * Send a proprietary event to all MediaControllers listening to this + * Session. It's up to the Controller/Session owner to determine the meaning + * of any events. * - * @param state + * @param event The name of the event to send + * @param extras Any extras included with the event */ - public void setPlaybackState(int state) { + public void sendEvent(String event, Bundle extras) { + if (TextUtils.isEmpty(event)) { + throw new IllegalArgumentException("event cannot be null or empty"); + } try { - mBinder.setPlaybackState(state); + mBinder.sendEvent(event, extras); } catch (RemoteException e) { - Log.e(TAG, "Dead object in setPlaybackState: ", e); + Log.wtf(TAG, "Error sending event", e); } } @@ -142,7 +237,7 @@ public final class MediaSession { try { mBinder.destroy(); } catch (RemoteException e) { - Log.e(TAG, "Dead object in onDestroy: ", e); + Log.wtf(TAG, "Error releasing session: ", e); } } @@ -158,15 +253,38 @@ public final class MediaSession { return mSessionToken; } - private void postCommand(String command, Bundle extras) { - Bundle commandBundle = new Bundle(); - commandBundle.putString(KEY_COMMAND, command); - commandBundle.putBundle(KEY_EXTRAS, extras); + private MessageHandler getHandlerForCallbackLocked(Callback cb) { + if (cb == null) { + throw new IllegalArgumentException("Callback cannot be null"); + } + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + MessageHandler handler = mCallbacks.get(i); + if (cb == handler.mCallback) { + return handler; + } + } + return null; + } + + private boolean removeCallbackLocked(Callback cb) { + if (cb == null) { + throw new IllegalArgumentException("Callback cannot be null"); + } + for (int i = mCallbacks.size() - 1; i >= 0; i--) { + MessageHandler handler = mCallbacks.get(i); + if (cb == handler.mCallback) { + mCallbacks.remove(i); + return true; + } + } + return false; + } + + private void postCommand(String command, Bundle extras, ResultReceiver resultCb) { + Command cmd = new Command(command, extras, resultCb); 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); + mCallbacks.get(i).post(MSG_COMMAND, cmd); } } } @@ -174,9 +292,7 @@ public final class MediaSession { 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); + mCallbacks.get(i).post(MSG_MEDIA_BUTTON, mediaButtonIntent); } } } @@ -184,9 +300,7 @@ public final class MediaSession { 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); + mCallbacks.get(i).post(MSG_ROUTE_CHANGE, mediaRouteDescriptor); } } } @@ -197,7 +311,6 @@ public final class MediaSession { * MediaSession (TODO). */ public abstract static class Callback { - private MessageHandler mHandler; public Callback() { } @@ -225,7 +338,7 @@ public final class MediaSession { * @param command * @param extras optional */ - public void onCommand(String command, Bundle extras) { + public void onCommand(String command, Bundle extras, ResultReceiver cb) { } /** @@ -237,35 +350,140 @@ public final class MediaSession { */ public void onRequestRouteChange(Bundle descriptor) { } - - private void setHandler(MessageHandler handler) { - mHandler = handler; - } } /** * @hide */ public static class CallbackStub extends IMediaSessionCallback.Stub { - private MediaSession mMediaSession; + private WeakReference<MediaSession> mMediaSession; public void setMediaSession(MediaSession session) { - mMediaSession = session; + mMediaSession = new WeakReference<MediaSession>(session); } @Override - public void onCommand(String command, Bundle extras) throws RemoteException { - mMediaSession.postCommand(command, extras); + public void onCommand(String command, Bundle extras, ResultReceiver cb) + throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + session.postCommand(command, extras, cb); + } } @Override public void onMediaButton(Intent mediaButtonIntent) throws RemoteException { - mMediaSession.postMediaButton(mediaButtonIntent); + MediaSession session = mMediaSession.get(); + if (session != null) { + session.postMediaButton(mediaButtonIntent); + } } @Override public void onRequestRouteChange(Bundle mediaRouteDescriptor) throws RemoteException { - mMediaSession.postRequestRouteChange(mediaRouteDescriptor); + MediaSession session = mMediaSession.get(); + if (session != null) { + session.postRequestRouteChange(mediaRouteDescriptor); + } + } + + @Override + public void onPlay() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onPlay(); + } + } + } + + @Override + public void onPause() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onPause(); + } + } + } + + @Override + public void onStop() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onStop(); + } + } + } + + @Override + public void onNext() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onNext(); + } + } + } + + @Override + public void onPrevious() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onPrevious(); + } + } + } + + @Override + public void onFastForward() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onFastForward(); + } + } + } + + @Override + public void onRewind() throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onRewind(); + } + } + } + + @Override + public void onSeekTo(long pos) throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onSeekTo(pos); + } + } + } + + @Override + public void onRate(Rating rating) throws RemoteException { + MediaSession session = mMediaSession.get(); + if (session != null) { + TransportPerformer tp = session.getTransportPerformer(); + if (tp != null) { + tp.onRate(rating); + } + } } } @@ -274,7 +492,7 @@ public final class MediaSession { private MediaSession.Callback mCallback; public MessageHandler(Looper looper, MediaSession.Callback callback) { - super(looper); + super(looper, null, true); mCallback = callback; } @@ -285,21 +503,35 @@ public final class MediaSession { return; } switch (msg.what) { - case MESSAGE_MEDIA_BUTTON: + case MSG_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); + case MSG_COMMAND: + Command cmd = (Command) msg.obj; + mCallback.onCommand(cmd.command, cmd.extras, cmd.stub); break; - case MESSAGE_ROUTE_CHANGE: + case MSG_ROUTE_CHANGE: mCallback.onRequestRouteChange((Bundle) msg.obj); break; } } msg.recycle(); } + + public void post(int what, Object obj) { + obtainMessage(what, obj).sendToTarget(); + } + } + + private static final class Command { + public final String command; + public final Bundle extras; + public final ResultReceiver stub; + + public Command(String command, Bundle extras, ResultReceiver stub) { + this.command = command; + this.extras = extras; + this.stub = stub; + } } } diff --git a/media/java/android/media/session/PlaybackState.aidl b/media/java/android/media/session/PlaybackState.aidl new file mode 100644 index 0000000..0876ebd --- /dev/null +++ b/media/java/android/media/session/PlaybackState.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.session; + +parcelable PlaybackState; diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java new file mode 100644 index 0000000..b3506b3 --- /dev/null +++ b/media/java/android/media/session/PlaybackState.java @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.media.session; + +import android.media.RemoteControlClient; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Playback state for a {@link MediaSession}. This includes a state like + * {@link PlaybackState#PLAYSTATE_PLAYING}, the current playback position, + * and the current control capabilities. + */ +public final class PlaybackState implements Parcelable { + /** + * Indicates this performer supports the stop command. + * + * @see #setActions + */ + public static final long ACTION_STOP = 1 << 0; + + /** + * Indicates this performer supports the pause command. + * + * @see #setActions + */ + public static final long ACTION_PAUSE = 1 << 1; + + /** + * Indicates this performer supports the play command. + * + * @see #setActions + */ + public static final long ACTION_PLAY = 1 << 2; + + /** + * Indicates this performer supports the rewind command. + * + * @see #setActions + */ + public static final long ACTION_REWIND = 1 << 3; + + /** + * Indicates this performer supports the previous command. + * + * @see #setActions + */ + public static final long ACTION_PREVIOUS_ITEM = 1 << 4; + + /** + * Indicates this performer supports the next command. + * + * @see #setActions + */ + public static final long ACTION_NEXT_ITEM = 1 << 5; + + /** + * Indicates this performer supports the fast forward command. + * + * @see #setActions + */ + public static final long ACTION_FASTFORWARD = 1 << 6; + + /** + * Indicates this performer supports the set rating command. + * + * @see #setActions + */ + public static final long ACTION_RATING = 1 << 7; + + /** + * Indicates this performer supports the seek to command. + * + * @see #setActions + */ + public static final long ACTION_SEEK_TO = 1 << 8; + + /** + * This is the default playback state and indicates that no media has been + * added yet, or the performer has been reset and has no content to play. + * + * @see #setState + */ + public final static int PLAYSTATE_NONE = 0; + + /** + * State indicating this item is currently stopped. + * + * @see #setState + */ + public final static int PLAYSTATE_STOPPED = 1; + + /** + * State indicating this item is currently paused. + * + * @see #setState + */ + public final static int PLAYSTATE_PAUSED = 2; + + /** + * State indicating this item is currently playing. + * + * @see #setState + */ + public final static int PLAYSTATE_PLAYING = 3; + + /** + * State indicating this item is currently fast forwarding. + * + * @see #setState + */ + public final static int PLAYSTATE_FAST_FORWARDING = 4; + + /** + * State indicating this item is currently rewinding. + * + * @see #setState + */ + public final static int PLAYSTATE_REWINDING = 5; + + /** + * State indicating this item is currently buffering and will begin playing + * when enough data has buffered. + * + * @see #setState + */ + public final static int PLAYSTATE_BUFFERING = 6; + + /** + * State indicating this item is currently in an error state. The error + * message should also be set when entering this state. + * + * @see #setState + */ + public final static int PLAYSTATE_ERROR = 7; + + private int mState; + private long mPosition; + private long mBufferPosition; + private float mSpeed; + private long mCapabilities; + private String mErrorMessage; + + /** + * Create an empty PlaybackState. At minimum a state and actions should be + * set before publishing a PlaybackState. + */ + public PlaybackState() { + } + + /** + * Create a new PlaybackState from an existing PlaybackState. All fields + * will be copied to the new state. + * + * @param from The PlaybackState to duplicate + */ + public PlaybackState(PlaybackState from) { + this.setState(from.getState()); + this.setPosition(from.getPosition()); + this.setBufferPosition(from.getBufferPosition()); + this.setSpeed(from.getSpeed()); + this.setActions(from.getActions()); + this.setErrorMessage(from.getErrorMessage()); + } + + private PlaybackState(Parcel in) { + this.setState(in.readInt()); + this.setPosition(in.readLong()); + this.setBufferPosition(in.readLong()); + this.setSpeed(in.readFloat()); + this.setActions(in.readLong()); + this.setErrorMessage(in.readString()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(getState()); + dest.writeLong(getPosition()); + dest.writeLong(getBufferPosition()); + dest.writeFloat(getSpeed()); + dest.writeLong(getActions()); + dest.writeString(getErrorMessage()); + } + + /** + * Get the current state of playback. One of the following: + * <ul> + * <li> {@link PlaybackState#PLAYSTATE_NONE}</li> + * <li> {@link PlaybackState#PLAYSTATE_STOPPED}</li> + * <li> {@link PlaybackState#PLAYSTATE_PLAYING}</li> + * <li> {@link PlaybackState#PLAYSTATE_PAUSED}</li> + * <li> {@link PlaybackState#PLAYSTATE_FAST_FORWARDING}</li> + * <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li> + * <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li> + * <li> {@link PlaybackState#PLAYSTATE_ERROR}</li> + */ + public int getState() { + return mState; + } + + /** + * Set the current state of playback. One of the following: + * <ul> + * <li> {@link PlaybackState#PLAYSTATE_NONE}</li> + * <li> {@link PlaybackState#PLAYSTATE_STOPPED}</li> + * <li> {@link PlaybackState#PLAYSTATE_PLAYING}</li> + * <li> {@link PlaybackState#PLAYSTATE_PAUSED}</li> + * <li> {@link PlaybackState#PLAYSTATE_FAST_FORWARDING}</li> + * <li> {@link PlaybackState#PLAYSTATE_REWINDING}</li> + * <li> {@link PlaybackState#PLAYSTATE_BUFFERING}</li> + * <li> {@link PlaybackState#PLAYSTATE_ERROR}</li> + */ + public void setState(int mState) { + this.mState = mState; + } + + /** + * Get the current playback position in ms. + */ + public long getPosition() { + return mPosition; + } + + /** + * Set the current playback position in ms. + */ + public void setPosition(long position) { + mPosition = position; + } + + /** + * Get the current buffer position in ms. This is the farthest playback + * point that can be reached from the current position using only buffered + * content. + */ + public long getBufferPosition() { + return mBufferPosition; + } + + /** + * Set the current buffer position in ms. This is the farthest playback + * point that can be reached from the current position using only buffered + * content. + */ + public void setBufferPosition(long bufferPosition) { + mBufferPosition = bufferPosition; + } + + /** + * Get the current playback speed as a multiple of normal playback. This + * should be negative when rewinding. A value of 1 means normal playback and + * 0 means paused. + */ + public float getSpeed() { + return mSpeed; + } + + /** + * Set the current playback speed as a multiple of normal playback. This + * should be negative when rewinding. A value of 1 means normal playback and + * 0 means paused. + */ + public void setSpeed(float speed) { + mSpeed = speed; + } + + /** + * Get the current actions available on this session. This should use a + * bitmask of the available actions. + * <ul> + * <li> {@link PlaybackState#ACTION_PREVIOUS_ITEM}</li> + * <li> {@link PlaybackState#ACTION_REWIND}</li> + * <li> {@link PlaybackState#ACTION_PLAY}</li> + * <li> {@link PlaybackState#ACTION_PAUSE}</li> + * <li> {@link PlaybackState#ACTION_STOP}</li> + * <li> {@link PlaybackState#ACTION_FASTFORWARD}</li> + * <li> {@link PlaybackState#ACTION_NEXT_ITEM}</li> + * <li> {@link PlaybackState#ACTION_SEEK_TO}</li> + * <li> {@link PlaybackState#ACTION_RATING}</li> + * </ul> + */ + public long getActions() { + return mCapabilities; + } + + /** + * Set the current capabilities available on this session. This should use a + * bitmask of the available capabilities. + * <ul> + * <li> {@link PlaybackState#ACTION_PREVIOUS_ITEM}</li> + * <li> {@link PlaybackState#ACTION_REWIND}</li> + * <li> {@link PlaybackState#ACTION_PLAY}</li> + * <li> {@link PlaybackState#ACTION_PAUSE}</li> + * <li> {@link PlaybackState#ACTION_STOP}</li> + * <li> {@link PlaybackState#ACTION_FASTFORWARD}</li> + * <li> {@link PlaybackState#ACTION_NEXT_ITEM}</li> + * <li> {@link PlaybackState#ACTION_SEEK_TO}</li> + * <li> {@link PlaybackState#ACTION_RATING}</li> + * </ul> + */ + public void setActions(long capabilities) { + mCapabilities = capabilities; + } + + /** + * Get a user readable error message. This should be set when the state is + * {@link PlaybackState#PLAYSTATE_ERROR}. + */ + public String getErrorMessage() { + return mErrorMessage; + } + + /** + * Set a user readable error message. This should be set when the state is + * {@link PlaybackState#PLAYSTATE_ERROR}. + */ + public void setErrorMessage(String errorMessage) { + mErrorMessage = errorMessage; + } + + public static final Parcelable.Creator<PlaybackState> CREATOR + = new Parcelable.Creator<PlaybackState>() { + @Override + public PlaybackState createFromParcel(Parcel in) { + return new PlaybackState(in); + } + + @Override + public PlaybackState[] newArray(int size) { + return new PlaybackState[size]; + } + }; +} diff --git a/media/java/android/media/session/RouteInterface.java b/media/java/android/media/session/RouteInterface.java new file mode 100644 index 0000000..2391f27 --- /dev/null +++ b/media/java/android/media/session/RouteInterface.java @@ -0,0 +1,187 @@ +/* + * 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.session; + +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Parcelable; +import android.os.ResultReceiver; + +/** + * Routes can support multiple interfaces for MediaSessions to interact with. To + * add a standard interface you should implement that interface's RouteInterface + * Stub and register it with the session. The set of supported commands is + * dependent on the specific interface's implementation. + * <p> + * A MediaInterface can be registered by calling TODO. Once added an interface + * will be used by Sessions to decide how they communicate with a session and + * cannot be removed, so all interfaces that you plan to support should be added + * when the route is created. + * + * @see RouteTransportControls + */ +public final class RouteInterface { + private static final String TAG = "MediaInterface"; + + private static final String KEY_RESULT = "result"; + + private final MediaController mController; + private final String mIface; + + /** + * @hide + */ + RouteInterface(MediaController controller, String iface) { + mController = controller; + mIface = iface; + } + + public void sendCommand(String command, Bundle params, ResultReceiver cb) { + // TODO + } + + public void addListener(EventListener listener) { + addListener(listener, null); + } + + public void addListener(EventListener listener, Handler handler) { + // TODO See MediaController for add/remove pattern + } + + public void removeListener(EventListener listener) { + // TODO + } + + // TODO decide on list of supported types + private static Bundle writeResultToBundle(Object v) { + Bundle b = new Bundle(); + if (v == null) { + // Don't send anything if null + } else if (v instanceof String) { + b.putString(KEY_RESULT, (String) v); + } else if (v instanceof Integer) { + b.putInt(KEY_RESULT, (Integer) v); + } else if (v instanceof Bundle) { + // Must be before Parcelable + b.putBundle(KEY_RESULT, (Bundle) v); + } else if (v instanceof Parcelable) { + b.putParcelable(KEY_RESULT, (Parcelable) v); + } else if (v instanceof Short) { + b.putShort(KEY_RESULT, (Short) v); + } else if (v instanceof Long) { + b.putLong(KEY_RESULT, (Long) v); + } else if (v instanceof Float) { + b.putFloat(KEY_RESULT, (Float) v); + } else if (v instanceof Double) { + b.putDouble(KEY_RESULT, (Double) v); + } else if (v instanceof Boolean) { + b.putBoolean(KEY_RESULT, (Boolean) v); + } else if (v instanceof CharSequence) { + // Must be after String + b.putCharSequence(KEY_RESULT, (CharSequence) v); + } else if (v instanceof boolean[]) { + b.putBooleanArray(KEY_RESULT, (boolean[]) v); + } else if (v instanceof byte[]) { + b.putByteArray(KEY_RESULT, (byte[]) v); + } else if (v instanceof String[]) { + b.putStringArray(KEY_RESULT, (String[]) v); + } else if (v instanceof CharSequence[]) { + // Must be after String[] and before Object[] + b.putCharSequenceArray(KEY_RESULT, (CharSequence[]) v); + } else if (v instanceof IBinder) { + b.putBinder(KEY_RESULT, (IBinder) v); + } else if (v instanceof Parcelable[]) { + b.putParcelableArray(KEY_RESULT, (Parcelable[]) v); + } else if (v instanceof int[]) { + b.putIntArray(KEY_RESULT, (int[]) v); + } else if (v instanceof long[]) { + b.putLongArray(KEY_RESULT, (long[]) v); + } else if (v instanceof Byte) { + b.putByte(KEY_RESULT, (Byte) v); + } + return b; + } + + public abstract static class Stub { + + /** + * The name of an interface should be a fully qualified name to prevent + * namespace collisions. Example: "com.myproject.MyPlaybackInterface" + * + * @return The name of this interface + */ + public abstract String getName(); + + /** + * This is called when a command is received that matches the interface + * you registered. Commands can come from any app with a MediaController + * reference to the session. + * + * @see MediaController + * @see MediaSession + * @param command The command or method to invoke. + * @param args Any args that were included with the command. May be + * null. + * @param cb The callback provided to send a response on. May be null. + */ + public abstract void onCommand(String command, Bundle args, ResultReceiver cb); + + public final void sendEvent(MediaSession session, String event, Bundle extras) { + // TODO + } + } + + /** + * An EventListener can be registered by an app with TODO to handle events + * sent by the session on a specific interface. + */ + public static abstract class EventListener { + /** + * This is called when an event is received from the interface. Events + * are sent by the session owner and will be delivered to all + * controllers that are listening to the interface. + * + * @param event The event that occurred. + * @param args Any extras that were included with the event. May be + * null. + */ + public abstract void onEvent(String event, Bundle args); + } + + private static final class EventHandler extends Handler { + + private final RouteInterface.EventListener mListener; + + public EventHandler(Looper looper, RouteInterface.EventListener cb) { + super(looper, null, true); + mListener = cb; + } + + @Override + public void handleMessage(Message msg) { + mListener.onEvent((String) msg.obj, msg.getData()); + } + + public void postEvent(String event, Bundle args) { + Message msg = obtainMessage(0, event); + msg.setData(args); + msg.sendToTarget(); + } + } +} diff --git a/media/java/android/media/session/RouteTransportControls.java b/media/java/android/media/session/RouteTransportControls.java new file mode 100644 index 0000000..665fd10 --- /dev/null +++ b/media/java/android/media/session/RouteTransportControls.java @@ -0,0 +1,230 @@ +/* + * 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.session; + +import android.media.RemoteControlClient; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; +import android.text.TextUtils; +import android.util.Log; + +/** + * A standard media control interface for Routes. Routes can support multiple + * interfaces for MediaSessions to interact with. TODO rewrite for routes + */ +public final class RouteTransportControls { + private static final String TAG = "RouteTransportControls"; + public static final String NAME = "android.media.session.RouteTransportControls"; + + private static final String KEY_VALUE1 = "value1"; + + private static final String METHOD_FAST_FORWARD = "fastForward"; + private static final String METHOD_GET_CURRENT_POSITION = "getCurrentPosition"; + private static final String METHOD_GET_CAPABILITIES = "getCapabilities"; + + private static final String EVENT_PLAYSTATE_CHANGE = "playstateChange"; + private static final String EVENT_METADATA_CHANGE = "metadataChange"; + + private final MediaController mController; + private final RouteInterface mIface; + + private RouteTransportControls(RouteInterface iface, MediaController controller) { + mIface = iface; + mController = controller; + } + + public static RouteTransportControls from(MediaController controller) { +// MediaInterface iface = controller.getInterface(NAME); +// if (iface != null) { +// return new RouteTransportControls(iface, controller); +// } + return null; + } + + /** + * Send a play command to the route. TODO rename resume() and use messaging + * protocol, not KeyEvent + */ + public void play() { + // TODO + } + + /** + * Send a pause command to the session. + */ + public void pause() { + // TODO + } + + /** + * Set the rate at which to fastforward. Valid values are in the range [0,1] + * with actual rates depending on the implementation. + * + * @param rate + */ + public void fastForward(float rate) { + if (rate < 0 || rate > 1) { + throw new IllegalArgumentException("Rate must be between 0 and 1 inclusive"); + } + Bundle b = new Bundle(); + b.putFloat(KEY_VALUE1, rate); + mIface.sendCommand(METHOD_FAST_FORWARD, b, null); + } + + public void getCurrentPosition(ResultReceiver cb) { + mIface.sendCommand(METHOD_GET_CURRENT_POSITION, null, cb); + } + + public void getCapabilities(ResultReceiver cb) { + mIface.sendCommand(METHOD_GET_CAPABILITIES, null, cb); + } + + public void addListener(Listener listener) { + mIface.addListener(listener.mListener); + } + + public void addListener(Listener listener, Handler handler) { + mIface.addListener(listener.mListener, handler); + } + + public void removeListener(Listener listener) { + mIface.removeListener(listener.mListener); + } + + public static abstract class Stub extends RouteInterface.Stub { + private final MediaSession mSession; + + public Stub(MediaSession session) { + mSession = session; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public void onCommand(String method, Bundle extras, ResultReceiver cb) { + if (TextUtils.isEmpty(method)) { + return; + } + Bundle result; + if (METHOD_FAST_FORWARD.equals(method)) { + fastForward(extras.getFloat(KEY_VALUE1, -1)); + } else if (METHOD_GET_CURRENT_POSITION.equals(method)) { + if (cb != null) { + result = new Bundle(); + result.putLong(KEY_VALUE1, getCurrentPosition()); + cb.send(0, result); + } + } else if (METHOD_GET_CAPABILITIES.equals(method)) { + if (cb != null) { + result = new Bundle(); + result.putLong(KEY_VALUE1, getCapabilities()); + cb.send(0, result); + } + } + } + + /** + * Override to handle fast forwarding. Valid values are [0,1] inclusive. + * The interpretation of the rate is up to the implementation. If no + * rate was included with the command a rate of -1 will be used by + * default. + * + * @param rate The rate at which to fast forward as a multiplier + */ + public void fastForward(float rate) { + Log.w(TAG, "fastForward is not supported."); + } + + /** + * Override to handle getting the current position of playback in + * millis. + * + * @return The current position in millis or -1 + */ + public long getCurrentPosition() { + Log.w(TAG, "getCurrentPosition is not supported"); + return -1; + } + + /** + * Override to handle getting the set of capabilities currently + * available. + * + * @return A bit mask of the supported capabilities + */ + public long getCapabilities() { + Log.w(TAG, "getCapabilities is not supported"); + return 0; + } + + /** + * 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 final void updatePlaybackState(int state) { + Bundle extras = new Bundle(); + extras.putInt(KEY_VALUE1, state); + sendEvent(mSession, EVENT_PLAYSTATE_CHANGE, extras); + } + } + + /** + * Register this event listener using TODO to receive + * TransportControlInterface events from a session. + * + * @see RouteInterface.EventListener + */ + public static abstract class Listener { + + private RouteInterface.EventListener mListener = new RouteInterface.EventListener() { + @Override + public final void onEvent(String event, Bundle args) { + if (EVENT_PLAYSTATE_CHANGE.equals(event)) { + onPlaybackStateChange(args.getInt(KEY_VALUE1)); + } else if (EVENT_METADATA_CHANGE.equals(event)) { + onMetadataUpdate(args); + } + } + }; + + /** + * Override to handle updates to the playback state. Valid values are in + * {@link TransportPerformer}. 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 MediaMetadata}. + * + * @param metadata + */ + public void onMetadataUpdate(Bundle metadata) { + } + } + +} diff --git a/media/java/android/media/session/TransportController.java b/media/java/android/media/session/TransportController.java new file mode 100644 index 0000000..15b11f3 --- /dev/null +++ b/media/java/android/media/session/TransportController.java @@ -0,0 +1,342 @@ +/* + * 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.session; + +import android.media.Rating; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Interface for controlling media playback on a session. This allows an app to + * request changes in playback, retrieve the current playback state and + * metadata, and listen for changes to the playback state and metadata. + */ +public final class TransportController { + private static final String TAG = "TransportController"; + + private final Object mLock = new Object(); + private final ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>(); + private final IMediaController mBinder; + + /** + * @hide + */ + public TransportController(IMediaController binder) { + mBinder = binder; + } + + /** + * Start listening to changes in playback state. + */ + public void addStateListener(TransportStateListener listener) { + addStateListener(listener, null); + } + + public void addStateListener(TransportStateListener listener, Handler handler) { + if (listener == null) { + throw new IllegalArgumentException("Listener cannot be null"); + } + synchronized (mLock) { + if (getHandlerForListenerLocked(listener) != null) { + Log.w(TAG, "Listener is already added, ignoring"); + return; + } + if (handler == null) { + handler = new Handler(); + } + + MessageHandler msgHandler = new MessageHandler(handler.getLooper(), listener); + mListeners.add(msgHandler); + } + } + + /** + * Stop listening to changes in playback state. + */ + public void removeStateListener(TransportStateListener listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener cannot be null"); + } + synchronized (mLock) { + removeStateListenerLocked(listener); + } + } + + /** + * Request that the player start its playback at its current position. + */ + public void play() { + try { + mBinder.play(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling play.", e); + } + } + + /** + * Request that the player pause its playback and stay at its current + * position. + */ + public void pause() { + try { + mBinder.pause(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling pause.", e); + } + } + + /** + * Request that the player stop its playback; it may clear its state in + * whatever way is appropriate. + */ + public void stop() { + try { + mBinder.stop(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling stop.", e); + } + } + + /** + * Move to a new location in the media stream. + * + * @param pos Position to move to, in milliseconds. + */ + public void seekTo(long pos) { + try { + mBinder.seekTo(pos); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling seekTo.", e); + } + } + + /** + * Start fast forwarding. If playback is already fast forwarding this may + * increase the rate. + */ + public void fastForward() { + try { + mBinder.fastForward(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling fastForward.", e); + } + } + + /** + * Skip to the next item. + */ + public void next() { + try { + mBinder.next(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling next.", e); + } + } + + /** + * Start rewinding. If playback is already rewinding this may increase the + * rate. + */ + public void rewind() { + try { + mBinder.rewind(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling rewind.", e); + } + } + + /** + * Skip to the previous item. + */ + public void previous() { + try { + mBinder.previous(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling previous.", e); + } + } + + /** + * Rate the current content. This will cause the rating to be set for the + * current user. The Rating type must match the type returned by + * {@link #getRatingType()}. + * + * @param rating The rating to set for the current content + */ + public void rate(Rating rating) { + try { + mBinder.rate(rating); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling rate.", e); + } + } + + /** + * Get the rating type supported by the session. One of: + * <ul> + * <li>{@link Rating#RATING_NONE}</li> + * <li>{@link Rating#RATING_HEART}</li> + * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li> + * <li>{@link Rating#RATING_3_STARS}</li> + * <li>{@link Rating#RATING_4_STARS}</li> + * <li>{@link Rating#RATING_5_STARS}</li> + * <li>{@link Rating#RATING_PERCENTAGE}</li> + * </ul> + * + * @return The supported rating type + */ + public int getRatingType() { + try { + return mBinder.getRatingType(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getRatingType.", e); + return Rating.RATING_NONE; + } + } + + /** + * Get the current playback state for this session. + * + * @return The current PlaybackState or null + */ + public PlaybackState getPlaybackState() { + try { + return mBinder.getPlaybackState(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getPlaybackState.", e); + return null; + } + } + + /** + * Get the current metadata for this session. + * + * @return The current MediaMetadata or null. + */ + public MediaMetadata getMetadata() { + try { + return mBinder.getMetadata(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getMetadata.", e); + return null; + } + } + + /** + * @hide + */ + public final void postPlaybackStateChanged(PlaybackState state) { + synchronized (mLock) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + mListeners.get(i).post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE, state); + } + } + } + + /** + * @hide + */ + public final void postMetadataChanged(MediaMetadata metadata) { + synchronized (mLock) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + mListeners.get(i).post(MessageHandler.MSG_UPDATE_METADATA, + metadata); + } + } + } + + private MessageHandler getHandlerForListenerLocked(TransportStateListener listener) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + MessageHandler handler = mListeners.get(i); + if (listener == handler.mListener) { + return handler; + } + } + return null; + } + + private boolean removeStateListenerLocked(TransportStateListener listener) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + if (listener == mListeners.get(i).mListener) { + mListeners.remove(i); + return true; + } + } + return false; + } + + /** + * Register using {@link #addStateListener} to receive updates when there + * are playback changes on the session. + */ + public static abstract class TransportStateListener { + private MessageHandler mHandler; + /** + * Override to handle changes in playback state. + * + * @param state The new playback state of the session + */ + public void onPlaybackStateChanged(PlaybackState state) { + } + + /** + * Override to handle changes to the current metadata. + * + * @see MediaMetadata + * @param metadata The current metadata for the session or null + */ + public void onMetadataChanged(MediaMetadata metadata) { + } + + private void setHandler(Handler handler) { + mHandler = new MessageHandler(handler.getLooper(), this); + } + } + + private static class MessageHandler extends Handler { + private static final int MSG_UPDATE_PLAYBACK_STATE = 1; + private static final int MSG_UPDATE_METADATA = 2; + + private TransportStateListener mListener; + + public MessageHandler(Looper looper, TransportStateListener cb) { + super(looper, null, true); + mListener = cb; + } + + public void post(int msg, Object obj) { + obtainMessage(msg, obj).sendToTarget(); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_PLAYBACK_STATE: + mListener.onPlaybackStateChanged((PlaybackState) msg.obj); + break; + case MSG_UPDATE_METADATA: + mListener.onMetadataChanged((MediaMetadata) msg.obj); + break; + } + } + } + +} diff --git a/media/java/android/media/session/TransportPerformer.java b/media/java/android/media/session/TransportPerformer.java new file mode 100644 index 0000000..b96db20 --- /dev/null +++ b/media/java/android/media/session/TransportPerformer.java @@ -0,0 +1,357 @@ +/* + * 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.session; + +import android.media.AudioManager; +import android.media.Rating; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.util.Log; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +/** + * Allows broadcasting of playback changes. + */ +public final class TransportPerformer { + private static final String TAG = "TransportPerformer"; + private final Object mLock = new Object(); + private final ArrayList<MessageHandler> mListeners = new ArrayList<MessageHandler>(); + + private IMediaSession mBinder; + + /** + * @hide + */ + public TransportPerformer(IMediaSession binder) { + mBinder = binder; + } + + /** + * Add a listener to receive updates on. + * + * @param listener The callback object + */ + public void addListener(Listener listener) { + addListener(listener, null); + } + + /** + * Add a listener to receive updates on. The updates will be posted to the + * specified handler. If no handler is provided they will be posted to the + * caller's thread. + * + * @param listener The listener to receive updates on + * @param handler The handler to post the updates on + */ + public void addListener(Listener listener, Handler handler) { + if (listener == null) { + throw new IllegalArgumentException("Listener cannot be null"); + } + synchronized (mLock) { + if (getHandlerForListenerLocked(listener) != null) { + Log.w(TAG, "Listener is already added, ignoring"); + } + if (handler == null) { + handler = new Handler(); + } + MessageHandler msgHandler = new MessageHandler(handler.getLooper(), listener); + mListeners.add(msgHandler); + } + } + + /** + * Stop receiving updates on the specified handler. If an update has already + * been posted you may still receive it after this call returns. + * + * @param listener The listener to stop receiving updates on + */ + public void removeListener(Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener cannot be null"); + } + synchronized (mLock) { + removeListenerLocked(listener); + } + } + + /** + * Update the current playback state. + * + * @param state The current state of playback + */ + public final void setPlaybackState(PlaybackState state) { + try { + mBinder.setPlaybackState(state); + } catch (RemoteException e) { + Log.wtf(TAG, "Dead object in setPlaybackState.", e); + } + } + + /** + * Update the current metadata. New metadata can be created using + * {@link MediaMetadata.Builder}. + * + * @param metadata The new metadata + */ + public final void setMetadata(MediaMetadata metadata) { + try { + mBinder.setMetadata(metadata); + } catch (RemoteException e) { + Log.wtf(TAG, "Dead object in setPlaybackState.", e); + } + } + + /** + * @hide + */ + public final void onPlay() { + post(MessageHandler.MESSAGE_PLAY); + } + + /** + * @hide + */ + public final void onPause() { + post(MessageHandler.MESSAGE_PAUSE); + } + + /** + * @hide + */ + public final void onStop() { + post(MessageHandler.MESSAGE_STOP); + } + + /** + * @hide + */ + public final void onNext() { + post(MessageHandler.MESSAGE_NEXT); + } + + /** + * @hide + */ + public final void onPrevious() { + post(MessageHandler.MESSAGE_PREVIOUS); + } + + /** + * @hide + */ + public final void onFastForward() { + post(MessageHandler.MESSAGE_FAST_FORWARD); + } + + /** + * @hide + */ + public final void onRewind() { + post(MessageHandler.MESSAGE_REWIND); + } + + /** + * @hide + */ + public final void onSeekTo(long pos) { + post(MessageHandler.MESSAGE_SEEK_TO, pos); + } + + /** + * @hide + */ + public final void onRate(Rating rating) { + post(MessageHandler.MESSAGE_RATE, rating); + } + + private MessageHandler getHandlerForListenerLocked(Listener listener) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + MessageHandler handler = mListeners.get(i); + if (listener == handler.mListener) { + return handler; + } + } + return null; + } + + private boolean removeListenerLocked(Listener listener) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + if (listener == mListeners.get(i).mListener) { + mListeners.remove(i); + return true; + } + } + return false; + } + + private void post(int what, Object obj) { + synchronized (mLock) { + for (int i = mListeners.size() - 1; i >= 0; i--) { + mListeners.get(i).post(what, obj); + } + } + } + + private void post(int what) { + post(what, null); + } + + /** + * Extend Listener to handle transport controls. Listeners can be registered + * using {@link #addListener}. + */ + public static abstract class Listener { + + /** + * Override to handle requests to begin playback. + */ + public void onPlay() { + } + + /** + * Override to handle requests to pause playback. + */ + public void onPause() { + } + + /** + * Override to handle requests to skip to the next media item. + */ + public void onNext() { + } + + /** + * Override to handle requests to skip to the previous media item. + */ + public void onPrevious() { + } + + /** + * Override to handle requests to fast forward. + */ + public void onFastForward() { + } + + /** + * Override to handle requests to rewind. + */ + public void onRewind() { + } + + /** + * Override to handle requests to stop playback. + */ + public void onStop() { + } + + /** + * Override to handle requests to seek to a specific position in ms. + * + * @param pos New position to move to, in milliseconds. + */ + public void onSeekTo(long pos) { + } + + /** + * Override to handle the item being rated. + * + * @param rating + */ + public void onRate(Rating rating) { + } + + /** + * Report that audio focus has changed on the app. This only happens if + * you have indicated you have started playing with + * {@link #setPlaybackState}. TODO figure out route focus apis/handling. + * + * @param focusChange The type of focus change, TBD. The default + * implementation will deliver a call to {@link #onPause} + * when focus is lost. + */ + public void onRouteFocusChange(int focusChange) { + switch (focusChange) { + case AudioManager.AUDIOFOCUS_LOSS: + onPause(); + break; + } + } + } + + private class MessageHandler extends Handler { + private static final int MESSAGE_PLAY = 1; + private static final int MESSAGE_PAUSE = 2; + private static final int MESSAGE_STOP = 3; + private static final int MESSAGE_NEXT = 4; + private static final int MESSAGE_PREVIOUS = 5; + private static final int MESSAGE_FAST_FORWARD = 6; + private static final int MESSAGE_REWIND = 7; + private static final int MESSAGE_SEEK_TO = 8; + private static final int MESSAGE_RATE = 9; + + private Listener mListener; + + public MessageHandler(Looper looper, Listener cb) { + super(looper); + mListener = cb; + } + + public void post(int what, Object obj) { + obtainMessage(what, obj).sendToTarget(); + } + + public void post(int what) { + post(what, null); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MESSAGE_PLAY: + mListener.onPlay(); + break; + case MESSAGE_PAUSE: + mListener.onPause(); + break; + case MESSAGE_STOP: + mListener.onStop(); + break; + case MESSAGE_NEXT: + mListener.onNext(); + break; + case MESSAGE_PREVIOUS: + mListener.onPrevious(); + break; + case MESSAGE_FAST_FORWARD: + mListener.onFastForward(); + break; + case MESSAGE_REWIND: + mListener.onRewind(); + break; + case MESSAGE_SEEK_TO: + mListener.onSeekTo((Long) msg.obj); + break; + case MESSAGE_RATE: + mListener.onRate((Rating) msg.obj); + break; + } + } + } +} diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 2ddbb7d..15ae238 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -596,6 +596,11 @@ public class MtpDatabase { MtpConstants.PROPERTY_DURATION, MtpConstants.PROPERTY_GENRE, MtpConstants.PROPERTY_COMPOSER, + MtpConstants.PROPERTY_AUDIO_WAVE_CODEC, + MtpConstants.PROPERTY_BITRATE_TYPE, + MtpConstants.PROPERTY_AUDIO_BITRATE, + MtpConstants.PROPERTY_NUMBER_OF_CHANNELS, + MtpConstants.PROPERTY_SAMPLE_RATE, }; static final int[] VIDEO_PROPERTIES = { diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index ea75a18..82c6a80 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -1000,6 +1000,22 @@ MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle, MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property, MtpObjectFormat format) { + static const int channelEnum[] = { + 1, // mono + 2, // stereo + 3, // 2.1 + 4, // 3 + 5, // 3.1 + 6, // 4 + 7, // 4.1 + 8, // 5 + 9, // 5.1 + }; + static const int bitrateEnum[] = { + 1, // fixed rate + 2, // variable rate + }; + MtpProperty* result = NULL; switch (property) { case MTP_PROPERTY_OBJECT_FORMAT: @@ -1013,6 +1029,7 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property, case MTP_PROPERTY_STORAGE_ID: case MTP_PROPERTY_PARENT_OBJECT: case MTP_PROPERTY_DURATION: + case MTP_PROPERTY_AUDIO_WAVE_CODEC: result = new MtpProperty(property, MTP_TYPE_UINT32); break; case MTP_PROPERTY_OBJECT_SIZE: @@ -1041,6 +1058,22 @@ MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property, // We allow renaming files and folders result = new MtpProperty(property, MTP_TYPE_STR, true); break; + case MTP_PROPERTY_BITRATE_TYPE: + result = new MtpProperty(property, MTP_TYPE_UINT16); + result->setFormEnum(bitrateEnum, sizeof(bitrateEnum)/sizeof(bitrateEnum[0])); + break; + case MTP_PROPERTY_AUDIO_BITRATE: + result = new MtpProperty(property, MTP_TYPE_UINT32); + result->setFormRange(1, 1536000, 1); + break; + case MTP_PROPERTY_NUMBER_OF_CHANNELS: + result = new MtpProperty(property, MTP_TYPE_UINT16); + result->setFormEnum(channelEnum, sizeof(channelEnum)/sizeof(channelEnum[0])); + break; + case MTP_PROPERTY_SAMPLE_RATE: + result = new MtpProperty(property, MTP_TYPE_UINT32); + result->setFormRange(8000, 48000, 1); + break; } return result; diff --git a/media/mca/filterfw/native/core/gl_env.cpp b/media/mca/filterfw/native/core/gl_env.cpp index 84dad8c..f092af8 100644 --- a/media/mca/filterfw/native/core/gl_env.cpp +++ b/media/mca/filterfw/native/core/gl_env.cpp @@ -162,9 +162,11 @@ bool GLEnv::InitWithNewContext() { } // Create dummy surface using a GLConsumer - sp<BufferQueue> bq = new BufferQueue(); - surfaceTexture_ = new GLConsumer(bq, 0); - window_ = new Surface(static_cast<sp<IGraphicBufferProducer> >(bq)); + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + surfaceTexture_ = new GLConsumer(consumer, 0); + window_ = new Surface(producer); surfaces_[0] = SurfaceWindowPair(eglCreateWindowSurface(display(), config, window_.get(), NULL), NULL); if (CheckEGLError("eglCreateWindowSurface")) return false; diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml index 1c1ba8b..f1be722 100644 --- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml +++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml @@ -44,7 +44,7 @@ <string name="root_type_shortcut" msgid="3318760609471618093">"Atalhos"</string> <string name="root_type_device" msgid="7121342474653483538">"Dispositivos"</string> <string name="root_type_apps" msgid="8838065367985945189">"Mais aplicações"</string> - <string name="pref_advanced_devices" msgid="903257239609301276">"Apresentar dispositivos avançados"</string> + <string name="pref_advanced_devices" msgid="903257239609301276">"Ver dispositivos avançados"</string> <string name="pref_file_size" msgid="2826879315743961459">"Apresentar tamanho do ficheiro"</string> <string name="pref_device_size" msgid="3542106883278997222">"Apresentar tamanho do dispositivo"</string> <string name="empty" msgid="7858882803708117596">"Sem itens"</string> diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml index ebe678e..933ef9c 100644 --- a/packages/Keyguard/res/values-am/strings.xml +++ b/packages/Keyguard/res/values-am/strings.xml @@ -82,7 +82,7 @@ <string name="password_keyboard_label_alpha_key" msgid="8001096175167485649">"ABC"</string> <string name="password_keyboard_label_alt_key" msgid="1284820942620288678">"ALT"</string> <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string> - <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ተወው"</string> + <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string> <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string> <string name="keyboardview_keycode_done" msgid="1992571118466679775">"ተከናውኗል"</string> <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"ሞድ ለውጥ"</string> diff --git a/packages/PrintSpooler/res/values-am/strings.xml b/packages/PrintSpooler/res/values-am/strings.xml index 3b94d6d..d86acb8 100644 --- a/packages/PrintSpooler/res/values-am/strings.xml +++ b/packages/PrintSpooler/res/values-am/strings.xml @@ -58,7 +58,7 @@ <item quantity="one" msgid="5866624638054847057">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> የህትመት ስራ"</item> <item quantity="other" msgid="8746611264734222865">"<xliff:g id="PRINT_JOB_NAME">%1$d</xliff:g> የህትመት ስራዎች"</item> </plurals> - <string name="cancel" msgid="4373674107267141885">"ሰርዝ"</string> + <string name="cancel" msgid="4373674107267141885">"ይቅር"</string> <string name="restart" msgid="2472034227037808749">"እንደገና ጀምር"</string> <string name="no_connection_to_printer" msgid="2159246915977282728">"ከአታሚ ጋር ምንም ግንኙነት የለም"</string> <string name="reason_unknown" msgid="5507940196503246139">"አይታወቅም"</string> diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 56c1f4e..1693e01 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -58,12 +58,6 @@ android:layout_height="@dimen/notification_panel_header_height" /> - <com.android.systemui.statusbar.phone.ZenModeView - android:id="@+id/zenmode" - android:layout_width="match_parent" - android:layout_height="wrap_content" - /> - <TextView android:id="@+id/emergency_calls_only" android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly" diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 25c516b..9aa7cfd 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -15,7 +15,7 @@ ** limitations under the License. --> -<com.android.systemui.statusbar.phone.PanelHeaderView +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/header" @@ -106,4 +106,4 @@ android:contentDescription="@string/accessibility_notifications_button" /> </FrameLayout> -</com.android.systemui.statusbar.phone.PanelHeaderView> +</LinearLayout> diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 31428b4..98d132a 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Kleur-omkeringmodus"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Verbeterde kontrasmodus"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Kleurregstellingmodus"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ONLANGS"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk word\ndalk gemonitor"</string> <string name="description_target_search" msgid="3091587249776033139">"Soek"</string> <string name="description_direction_up" msgid="7169032478259485180">"Gly op vir <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index e393c90..d7457f0 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"የተቃራኒ ቀለም ሁነታ"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"የተሻሻለ ንፅፅር ሁነታ"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"የቀለም እርማት ሁነታ"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"የቅርብ ጊዜዎች"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"አውታረ መረብ\nክትትል ሊደረግበት ይችላል"</string> <string name="description_target_search" msgid="3091587249776033139">"ፍለጋ"</string> <string name="description_direction_up" msgid="7169032478259485180">"ለ<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ወደ ላይ አንሸራትት።"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 0060004..596f612 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"وضع انعكاس اللون"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"وضع التباين المحسن"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"وضع تصحيح الألوان"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"الأخيرة"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"قد تكون الشبكة\nخاضعة للرقابة"</string> <string name="description_target_search" msgid="3091587249776033139">"بحث"</string> <string name="description_direction_up" msgid="7169032478259485180">"تمرير لأعلى لـ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 1488864..335c33a 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим на инвертиране на цветовете"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим на подобрен контраст"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим на коригиране на цветовете"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"СКОРОШНИ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежата може\nда се наблюдава"</string> <string name="description_target_search" msgid="3091587249776033139">"Търсене"</string> <string name="description_direction_up" msgid="7169032478259485180">"Плъзнете нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 329e91f..e79e094 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversió de color"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode de contrast millorat"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correcció de color"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"És possible que la xarxa\nestigui controlada"</string> <string name="description_target_search" msgid="3091587249776033139">"Cerca"</string> <string name="description_direction_up" msgid="7169032478259485180">"Fes lliscar el dit cap amunt per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index b326220..60bbe3b 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Režim převrácení barev"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Režim zvýšeného kontrastu"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekce barev"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"POSLEDNÍ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Síť může být\nmonitorována"</string> <string name="description_target_search" msgid="3091587249776033139">"Vyhledávání"</string> <string name="description_direction_up" msgid="7169032478259485180">"Přejeďte prstem nahoru: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index f0db449..9c920f2 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Farveinverteringstilstand"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Tilstand for forbedret kontrast"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"SENESTE"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netværket kan\nvære overvåget"</string> <string name="description_target_search" msgid="3091587249776033139">"Søgning"</string> <string name="description_direction_up" msgid="7169032478259485180">"Glid op for at <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index fd41752..c8cb0a4 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Farbinversionsmodus"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastverbesserungsmodus"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Farbkorrekturmodus"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"Letzte"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netzwerk wird\neventuell überwacht."</string> <string name="description_target_search" msgid="3091587249776033139">"Suche"</string> <string name="description_direction_up" msgid="7169032478259485180">"Zum <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> nach oben schieben"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 96e2aaa..79025b6 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Λειτουργία αναστροφής χρώματος"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Λειτουργία βελτίωσης αντίθεσης"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Λειτουργία διόρθωσης χρώματος"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ΠΡΟΣΦΑΤΑ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Το δίκτυο μπορεί\nνα παρακολουθείται"</string> <string name="description_target_search" msgid="3091587249776033139">"Αναζήτηση"</string> <string name="description_direction_up" msgid="7169032478259485180">"Κύλιση προς τα επάνω για <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 342061e..338c8ac 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Enhanced contrast mode"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string> <string name="description_target_search" msgid="3091587249776033139">"Search"</string> <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 342061e..338c8ac 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Colour inversion mode"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Enhanced contrast mode"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Colour correction mode"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTS"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Network may\nbe monitored"</string> <string name="description_target_search" msgid="3091587249776033139">"Search"</string> <string name="description_direction_up" msgid="7169032478259485180">"Slide up for <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index a82e2d7..89fe58b 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversión de color"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste mejorado"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Es posible que la red\nesté supervisada."</string> <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 2a977ee..4999f71 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversión de color"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste mejorado"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de corrección de color"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECIENTES"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La red se\npuede supervisar"</string> <string name="description_target_search" msgid="3091587249776033139">"Buscar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Desliza el dedo hacia arriba para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml index 821c1dd..b734fa8 100644 --- a/packages/SystemUI/res/values-et-rEE/strings.xml +++ b/packages/SystemUI/res/values-et-rEE/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Värvide ümberpööramise režiim"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Täiustatud kontrasti režiim"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Värviparandusrežiim"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"HILJUTISED"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Võrku võidakse\njälgida"</string> <string name="description_target_search" msgid="3091587249776033139">"Otsing"</string> <string name="description_direction_up" msgid="7169032478259485180">"Lohistage üles: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 2cb40a0..5780a57 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"حالت وارونگی رنگ"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"حالت کنتراست بهبودیافته"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"حالت تصحیح رنگ"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"موارد اخیر"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ممکن است شبکه\nتحت نظارت باشد"</string> <string name="description_target_search" msgid="3091587249776033139">"جستجو"</string> <string name="description_direction_up" msgid="7169032478259485180">"لغزاندن به بالا برای <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 41a0bd4..4809741 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Käänteinen väritila"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastinparannustila"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Värinkorjaustila"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"VIIMEISIMMÄT"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Verkkoa saatetaan\nvalvoa"</string> <string name="description_target_search" msgid="3091587249776033139">"Haku"</string> <string name="description_direction_up" msgid="7169032478259485180">"Liu\'uta ylös ja <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 60823b5..36b54ce 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversion des couleurs"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode d\'accentuation du contraste"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correction des couleurs"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string> <string name="description_target_search" msgid="3091587249776033139">"Recherche"</string> <string name="description_direction_up" msgid="7169032478259485180">"Faire glisser le doigt vers le haut : <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 5d6368e..5b81975 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode d\'inversion des couleurs"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode d\'accentuation du contraste"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode de correction des couleurs"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RÉCENTS"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Le réseau peut\nêtre surveillé."</string> <string name="description_target_search" msgid="3091587249776033139">"Rechercher"</string> <string name="description_direction_up" msgid="7169032478259485180">"Faites glisser vers le haut pour <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 3167fe7..9be9550 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"रंग व्युत्क्रम मोड"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"उन्नत कंट्रास्ट मोड"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"रंग सुधार मोड"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"हाल ही का"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"नेटवर्क को\nमॉनीटर किया जा सकता है"</string> <string name="description_target_search" msgid="3091587249776033139">"खोजें"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> के लिए ऊपर स्लाइड करें."</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 529f891..21d6ef5 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije boje"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Način pojačanog kontrasta"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Način korekcije boje"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNO"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mreža se\nmožda prati"</string> <string name="description_target_search" msgid="3091587249776033139">"Pretraživanje"</string> <string name="description_direction_up" msgid="7169032478259485180">"Kliznite prema gore za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 7e064dd..8e6ee4f 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Színinvertálás mód"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrasztjavítás mód"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Színjavítás mód"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"LEGUTÓBBIAK"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Lehet, hogy a\nhálózat felügyelt"</string> <string name="description_target_search" msgid="3091587249776033139">"Keresés"</string> <string name="description_direction_up" msgid="7169032478259485180">"A(z) <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> művelethez csúsztassa felfelé."</string> diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml index 1124163..a787983 100644 --- a/packages/SystemUI/res/values-hy-rAM/strings.xml +++ b/packages/SystemUI/res/values-hy-rAM/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Գունաշրջման ռեժիմ"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Ընդլայնված ցայտունության ռեժիմ"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Գույների կարգավորման ռեժիմ"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ՎԵՐՋԻՆՆԵՐԸ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ցանցը կարող է\nվերահսկվել"</string> <string name="description_target_search" msgid="3091587249776033139">"Որոնել"</string> <string name="description_direction_up" msgid="7169032478259485180">"Սահեցրեք վերև <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-ի համար:"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 167b101..13fc534 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode inversi warna"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode kontras yang disempurnakan"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode koreksi warna"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"TERBARU"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Jaringan bisa\ndiawasi"</string> <string name="description_target_search" msgid="3091587249776033139">"Telusuri"</string> <string name="description_direction_up" msgid="7169032478259485180">"Geser ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 6321870..71a644d 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modalità inversione colori"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modalità di contrasto avanzata"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modalità di correzione del colore"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ELEMENTI RECENTI"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"La rete potrebbe\nessere monitorata"</string> <string name="description_target_search" msgid="3091587249776033139">"Ricerca"</string> <string name="description_direction_up" msgid="7169032478259485180">"Su per <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 24114f7..798e8c3 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"מצב היפוך צבעים"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"מצב ניגודיות מוגברת"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"מצב תיקון צבע"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"אחרונים"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ייתכן שהרשת\nמנוטרת"</string> <string name="description_target_search" msgid="3091587249776033139">"חיפוש"</string> <string name="description_direction_up" msgid="7169032478259485180">"הסט למעלה כדי להציג <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 0bee9f0..c5070a8 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"色反転モード"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"拡張コントラストモード"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"色補正モード"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"最近"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ネットワークが監視される\n場合があります"</string> <string name="description_target_search" msgid="3091587249776033139">"検索します"</string> <string name="description_direction_up" msgid="7169032478259485180">"上にスライドして<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>を行います。"</string> diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml index fe0a047..bbdce19 100644 --- a/packages/SystemUI/res/values-ka-rGE/strings.xml +++ b/packages/SystemUI/res/values-ka-rGE/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"ფერთა ინვერსიის რეჟიმი"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"გაუმჯობესებული კონტრასტის რეჟიმი"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"ფერთა კორექციის რეჟიმი"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ბოლო დროის"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"შესაძლოა ქსელზე\nმონიტორინგი ხორციელდებოდეს"</string> <string name="description_target_search" msgid="3091587249776033139">"ძიება"</string> <string name="description_direction_up" msgid="7169032478259485180">"გაასრიალეთ ზემოთ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-თვის."</string> diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml index 470309a..61ca77d 100644 --- a/packages/SystemUI/res/values-km-rKH/strings.xml +++ b/packages/SystemUI/res/values-km-rKH/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"របៀបបញ្ច្រាសពណ៌"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"របៀបកម្រិតពណ៌ប្រសើរឡើង"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"របៀបកែពណ៌"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ថ្មីៗ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"បណ្ដាញអាច\nត្រូវបានត្រួតពិនិត្យ"</string> <string name="description_target_search" msgid="3091587249776033139">"ស្វែងរក"</string> <string name="description_direction_up" msgid="7169032478259485180">"រុញឡើងលើដើម្បី <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ។"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index f72549d..8108daa 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"색상 반전 모드"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"향상된 대비 모드"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"색상 보정 모드"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"최근"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"네트워크가\n모니터링될 수 있음"</string> <string name="description_target_search" msgid="3091587249776033139">"검색"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>하려면 위로 슬라이드"</string> diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml index 59cf520..c2e5990 100644 --- a/packages/SystemUI/res/values-lo-rLA/strings.xml +++ b/packages/SystemUI/res/values-lo-rLA/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"ໂໝດສະລັບສີ"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"ໂໝດຄວາມຕ່າງແສງ"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"ໂໝດການແກ້ໄຂສີ"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ບໍ່ດົນມານີ້"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"ເຄືອຄ່າຍອາດ\nຖືກຕິດຕາມ"</string> <string name="description_target_search" msgid="3091587249776033139">"ຊອກຫາ"</string> <string name="description_direction_up" msgid="7169032478259485180">"ເລື່ອນຂຶ້ນເພື່ອ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 29ca84a..1d8b051 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Spalvų inversijos režimas"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Patobulinto kontrasto režimas"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Spalvų taisymo režimas"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"PASTARIEJI"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tinklas gali\nbūti stebimas"</string> <string name="description_target_search" msgid="3091587249776033139">"Paieška"</string> <string name="description_direction_up" msgid="7169032478259485180">"Slyskite aukštyn link <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 4230b2e..603fa1a 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Krāsu inversijas režīms"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Uzlabota kontrasta režīms"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Krāsu korekcijas režīms"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"JAUNĀKIE"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tīkls var\ntikt uzraudzīts"</string> <string name="description_target_search" msgid="3091587249776033139">"Meklēt"</string> <string name="description_direction_up" msgid="7169032478259485180">"Velciet uz augšu, lai veiktu šādu darbību: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml index d6c68bc..110cfd2 100644 --- a/packages/SystemUI/res/values-mn-rMN/strings.xml +++ b/packages/SystemUI/res/values-mn-rMN/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Өнгө урвуулах горим"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Сайжруулсан ялгаралтай горим"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Өнгө залруулах горим"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"СҮҮЛИЙН"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Сүлжээ хянагдаж\nбайж болзошгүй"</string> <string name="description_target_search" msgid="3091587249776033139">"Хайх"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>-г гулсуулах."</string> diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml index 114d03e..62c90ab 100644 --- a/packages/SystemUI/res/values-ms-rMY/strings.xml +++ b/packages/SystemUI/res/values-ms-rMY/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mod penyongsangan warna"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mod kontras dipertingkat"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod pembetulan warna"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"TERBAHARU"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rangkaian mungkin\nboleh dipantau"</string> <string name="description_target_search" msgid="3091587249776033139">"Carian"</string> <string name="description_direction_up" msgid="7169032478259485180">"Luncurkan ke atas untuk <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 12deaef..0e914ea 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus for fargeinvertering"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Forbedret kontrastmodus"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus for fargekorrigering"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"NYLIGE"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nettverket kan\nvære overvåket"</string> <string name="description_target_search" msgid="3091587249776033139">"Søk"</string> <string name="description_direction_up" msgid="7169032478259485180">"Dra opp for å <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 59c64b5..6e09131 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modus voor kleurinversie"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modus voor verbeterd contrast"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modus voor kleurcorrectie"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTEN"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Netwerk kan\nworden gecontroleerd"</string> <string name="description_target_search" msgid="3091587249776033139">"Zoeken"</string> <string name="description_direction_up" msgid="7169032478259485180">"Veeg omhoog voor <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index b2628e1..c21230c 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Tryb odwrócenia kolorów"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Tryb zwiększonego kontrastu"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Tryb korekcji kolorów"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"OSTATNIE"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieć może być\nmonitorowana"</string> <string name="description_target_search" msgid="3091587249776033139">"Szukaj"</string> <string name="description_direction_up" msgid="7169032478259485180">"Przesuń w górę: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index fc25ea8..771daf2 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversão de cor"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste melhorado"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode ser\nmonitorizada"</string> <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Deslize para cima para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index e077fc6..b643bae 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Modo de inversão de cores"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Modo de contraste aprimorado"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Modo de correção de cor"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTES"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"A rede pode estar\nsob monitoração"</string> <string name="description_target_search" msgid="3091587249776033139">"Pesquisar"</string> <string name="description_direction_up" msgid="7169032478259485180">"Para <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>, deslize para cima."</string> diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml index adf54bc..33cb355 100644 --- a/packages/SystemUI/res/values-rm/strings.xml +++ b/packages/SystemUI/res/values-rm/strings.xml @@ -378,6 +378,8 @@ <skip /> <!-- no translation found for quick_settings_color_space_label (853443689745584770) --> <skip /> + <!-- no translation found for recents_empty_message (2269156590813544104) --> + <skip /> <!-- no translation found for ssl_ca_cert_warning (9005954106902053641) --> <skip /> <!-- no translation found for description_target_search (3091587249776033139) --> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 9cfb329..87f9c0c 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mod de inversare a culorilor"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mod contrast îmbunătățit"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mod de corectare a culorilor"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"RECENTE"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Rețeaua poate\nfi monitorizată"</string> <string name="description_target_search" msgid="3091587249776033139">"Căutaţi"</string> <string name="description_direction_up" msgid="7169032478259485180">"Glisaţi în sus pentru <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 7a89d27..e79a0dd 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -208,6 +208,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Инверсия цвета"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Контрастность"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Коррекция цвета"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"НЕДАВНИЕ СООБЩЕНИЯ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Действия в сети\nмогут отслеживаться"</string> <string name="description_target_search" msgid="3091587249776033139">"Поиск"</string> <string name="description_direction_up" msgid="7169032478259485180">"Проведите вверх, чтобы <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 13c6094..d39c8bd 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Režim prevrátenia farieb"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Režim zvýšeného kontrastu"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Režim korekcie farieb"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"NEDÁVNE"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Sieť môže byť\nmonitorovaná"</string> <string name="description_target_search" msgid="3091587249776033139">"Vyhľadávanie"</string> <string name="description_direction_up" msgid="7169032478259485180">"Prejdite prstom nahor: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index a5b3244..c49b6c2 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Način inverzije barv"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Način izboljšanega kontrasta"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Način popravljanja barv"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"NEDAVNI"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Omrežje je\nlahko spremljano"</string> <string name="description_target_search" msgid="3091587249776033139">"Iskanje"</string> <string name="description_direction_up" msgid="7169032478259485180">"Povlecite navzgor za <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 0bdccee..89bc3c5 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим инверзије боје"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим унапређеног контраста"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим корекције боје"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"НАЈНОВИЈЕ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мрежа се можда\nнадгледа"</string> <string name="description_target_search" msgid="3091587249776033139">"Претрага"</string> <string name="description_direction_up" msgid="7169032478259485180">"Превуците нагоре за <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index efe7fcb..1b47be5 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Färginverteringsläge"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Kontrastförbättringsläge"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Färgkorrigeringsläge"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"NYA"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Nätverket kan\nvara övervakat"</string> <string name="description_target_search" msgid="3091587249776033139">"Sök"</string> <string name="description_direction_up" msgid="7169032478259485180">"Dra uppåt för <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 9336ade..3702196 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -202,6 +202,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Hali ya ugeuzaji kinyume wa rangi"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Hali ya utofautishaji ulioboreshwa"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Hali ya kusahihisha rangi"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"YA HIVI KARIBUNI"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Huenda mtandao\nunafuatiliwa"</string> <string name="description_target_search" msgid="3091587249776033139">"Tafuta"</string> <string name="description_direction_up" msgid="7169032478259485180">"Sogeza juu kwa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ."</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 033e56d..0d9be4c 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"โหมดการกลับสี"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"โหมดคอนทราสต์ที่ปรับปรุงแล้ว"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"โหมดการแก้ไขสี"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ล่าสุด"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"เครือข่ายอาจ\nถูกตรวจสอบ"</string> <string name="description_target_search" msgid="3091587249776033139">"ค้นหา"</string> <string name="description_direction_up" msgid="7169032478259485180">"เลื่อนขึ้นเพื่อ <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 3704c48..d7502cb 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Mode ng pag-invert ng kulay"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Mode na dinagdagan ang contrast"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Mode ng pagtatama ng kulay"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"MGA KAMAKAILAN"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Maaaring\nsinusubaybayan ang network"</string> <string name="description_target_search" msgid="3091587249776033139">"Maghanap"</string> <string name="description_direction_up" msgid="7169032478259485180">"Mag-slide pataas para sa <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 56e5c88..f56293b 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Renk ters çevirme modu"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Geliştirilmiş kontrast modu"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Renk düzeltme modu"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"SON İLETİLER"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Ağ izleniyor\nolabilir"</string> <string name="description_target_search" msgid="3091587249776033139">"Ara"</string> <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> için yukarı kaydırın."</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 3a474a4..df94b26 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Режим інверсії кольорів"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Режим посиленого контрасту"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Режим коригування кольору"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"ОСТАННІ"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Мережа може\nвідстежуватися"</string> <string name="description_target_search" msgid="3091587249776033139">"Пошук"</string> <string name="description_direction_up" msgid="7169032478259485180">"Проведіть пальцем угору, щоб <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 700c20d..471cbd3 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Chế độ đảo ngược màu sắc"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Chế độ tương phản tăng cường"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Chế độ hiệu chỉnh màu sắc"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"GẦN ĐÂY"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Mạng có thể\nđược giám sát"</string> <string name="description_target_search" msgid="3091587249776033139">"Tìm kiếm"</string> <string name="description_direction_up" msgid="7169032478259485180">"Trượt lên để <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 5909fbf..e53c1fb 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"颜色反转模式"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"增强对比度模式"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"颜色校正模式"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"最近"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"网络可能会\n受到监控"</string> <string name="description_target_search" msgid="3091587249776033139">"搜索"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑动以<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index d229347..d4defa4 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"色彩反轉模式"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"增強對比模式"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校準模式"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"近期"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網絡可能會\n受到監控"</string> <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index bf2d7ce..55399c2 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -206,6 +206,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"彩色反轉模式"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"增強對比模式"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"色彩校正模式"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"近期"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"網路可能\n受到監控"</string> <string name="description_target_search" msgid="3091587249776033139">"搜尋"</string> <string name="description_direction_up" msgid="7169032478259485180">"向上滑動即可<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>。"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index d676b5c..92e3382 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -204,6 +204,7 @@ <string name="quick_settings_inversion_label" msgid="1666358784283020762">"Imodi yokuguqulwa kombala"</string> <string name="quick_settings_contrast_label" msgid="3319507551689108692">"Imodi ethuthukisiwe yokugqama"</string> <string name="quick_settings_color_space_label" msgid="853443689745584770">"Imodi yokulungisa umbala"</string> + <string name="recents_empty_message" msgid="2269156590813544104">"OKWAKAMUVA"</string> <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Kungenzeka inethiwekhi\niqashiwe"</string> <string name="description_target_search" msgid="3091587249776033139">"Sesha"</string> <string name="description_direction_up" msgid="7169032478259485180">"Shelelisela ngenhla ku-<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string> diff --git a/packages/SystemUI/src/com/android/systemui/recents/Console.java b/packages/SystemUI/src/com/android/systemui/recents/Console.java index b3d9ccf..db95193 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Console.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Console.java @@ -17,6 +17,7 @@ package com.android.systemui.recents; +import android.content.ComponentCallbacks2; import android.content.Context; import android.util.Log; import android.view.MotionEvent; @@ -36,20 +37,20 @@ public class Console { /** Logs a key */ public static void log(String key) { - Console.log(true, key, "", AnsiReset); + log(true, key, "", AnsiReset); } /** Logs a conditioned key */ public static void log(boolean condition, String key) { if (condition) { - Console.log(condition, key, "", AnsiReset); + log(condition, key, "", AnsiReset); } } /** Logs a key in a specific color */ public static void log(boolean condition, String key, Object data) { if (condition) { - Console.log(condition, key, data, AnsiReset); + log(condition, key, data, AnsiReset); } } @@ -74,6 +75,50 @@ public class Console { } } + /** Logs a stack trace */ + public static void logStackTrace() { + logStackTrace("", 99); + } + + /** Logs a stack trace to a certain depth */ + public static void logStackTrace(int depth) { + logStackTrace("", depth); + } + + /** Logs a stack trace to a certain depth with a key */ + public static void logStackTrace(String key, int depth) { + int offset = 0; + StackTraceElement[] callStack = Thread.currentThread().getStackTrace(); + String tinyStackTrace = ""; + // Skip over the known stack trace classes + for (int i = 0; i < callStack.length; i++) { + StackTraceElement el = callStack[i]; + String className = el.getClassName(); + if (className.indexOf("dalvik.system.VMStack") == -1 && + className.indexOf("java.lang.Thread") == -1 && + className.indexOf("recents.Console") == -1) { + break; + } else { + offset++; + } + } + // Build the pretty stack trace + int start = Math.min(offset + depth, callStack.length); + int end = offset; + String indent = ""; + for (int i = start - 1; i >= end; i--) { + StackTraceElement el = callStack[i]; + tinyStackTrace += indent + " -> " + el.getClassName() + + "[" + el.getLineNumber() + "]." + el.getMethodName(); + if (i > end) { + tinyStackTrace += "\n"; + indent += " "; + } + } + log(true, key, tinyStackTrace, AnsiRed); + } + + /** Returns the stringified MotionEvent action */ public static String motionEventActionToString(int action) { switch (action) { @@ -93,4 +138,25 @@ public class Console { return "" + action; } } + + public static String trimMemoryLevelToString(int level) { + switch (level) { + case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN: + return "UI Hidden"; + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE: + return "Running Moderate"; + case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND: + return "Background"; + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW: + return "Running Low"; + case ComponentCallbacks2.TRIM_MEMORY_MODERATE: + return "Moderate"; + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL: + return "Critical"; + case ComponentCallbacks2.TRIM_MEMORY_COMPLETE: + return "Complete"; + default: + return "" + level; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index aeae4ab..62da17e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -28,11 +28,13 @@ public class Constants { public static class App { public static final boolean EnableTaskFiltering = false; public static final boolean EnableTaskStackClipping = false; - public static final boolean EnableBackgroundTaskLoading = true; - public static final boolean ForceDisableBackgroundCache = false; + // This disables the bitmap and icon caches to + public static final boolean DisableBackgroundCache = false; + public static final boolean TaskDataLoader = false; public static final boolean SystemUIHandshake = false; public static final boolean TimeSystemCalls = false; + public static final boolean Memory = false; } public static class UI { @@ -41,7 +43,7 @@ public class Constants { public static final boolean TouchEvents = false; public static final boolean MeasureAndLayout = false; public static final boolean Clipping = false; - public static final boolean HwLayers = true; + public static final boolean HwLayers = false; } public static class TaskStack { @@ -55,13 +57,16 @@ public class Constants { public static class Values { public static class Window { + // The dark background dim is set behind the empty recents view public static final float DarkBackgroundDim = 0.5f; + // The background dim is set behind the card stack public static final float BackgroundDim = 0.35f; } public static class RecentsTaskLoader { // XXX: This should be calculated on the first load public static final int PreloadFirstTasksCount = 5; + // For debugging, this allows us to multiply the number of cards for each task public static final int TaskEntryMultiplier = 1; } @@ -69,8 +74,6 @@ public class Constants { public static class Animation { public static final int TaskRemovedReshuffleDuration = 200; public static final int SnapScrollBackDuration = 650; - public static final int SwipeDismissDuration = 350; - public static final int SwipeSnapBackDuration = 350; } // The padding will be applied to the smallest dimension, and then applied to all sides diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index d050847..e3908ff 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -23,6 +23,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; import android.widget.FrameLayout; +import com.android.systemui.recent.RecentTasksLoader; import com.android.systemui.recents.model.SpaceNode; import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.RecentsView; @@ -44,7 +45,6 @@ public class RecentsActivity extends Activity { SpaceNode root = loader.reload(this, Constants.Values.RecentsTaskLoader.PreloadFirstTasksCount); ArrayList<TaskStack> stacks = root.getStacks(); if (!stacks.isEmpty()) { - // XXX: We just replace the root every time for now, we will change this in the future mRecentsView.setBSP(root); } @@ -154,7 +154,7 @@ public class RecentsActivity extends Activity { Console.AnsiRed); super.onPause(); - // Stop the loader when we leave Recents + // Stop the loader immediately when we leave Recents RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); loader.stopLoader(); } @@ -168,6 +168,14 @@ public class RecentsActivity extends Activity { } @Override + public void onTrimMemory(int level) { + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); + if (loader != null) { + loader.onTrimMemory(level); + } + } + + @Override public void onBackPressed() { if (!mRecentsView.unfilterFilteredStacks()) { super.onBackPressed(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index f3881ae..ed981ed 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -30,7 +30,6 @@ public class RecentsConfiguration { DisplayMetrics mDisplayMetrics; - public boolean layoutVerticalStack; public Rect systemInsets = new Rect(); /** Private constructor */ @@ -56,7 +55,6 @@ public class RecentsConfiguration { boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; - layoutVerticalStack = isPortrait || Constants.LANDSCAPE_LAYOUT_VERTICAL_STACK; } public void updateSystemInsets(Rect insets) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java index 522ab0f..46ff841 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsService.java @@ -30,18 +30,31 @@ import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.TaskStackView; import com.android.systemui.recents.views.TaskViewTransform; +import java.lang.ref.WeakReference; + /* Service */ public class RecentsService extends Service { // XXX: This should be getting the message from recents definition final static int MSG_UPDATE_RECENTS_FOR_CONFIGURATION = 0; - class MessageHandler extends Handler { + /** This Handler should be static to prevent holding onto a reference to the service. */ + static class MessageHandler extends Handler { + WeakReference<Context> mContext; + + MessageHandler(Context context) { + // Keep a weak ref to the context instead of a strong ref + mContext = new WeakReference<Context>(context); + } + @Override public void handleMessage(Message msg) { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|handleMessage]", msg); + Console.log(Constants.DebugFlags.App.SystemUIHandshake, + "[RecentsService|handleMessage]", msg); if (msg.what == MSG_UPDATE_RECENTS_FOR_CONFIGURATION) { - Context context = RecentsService.this; + Context context = mContext.get(); + if (context == null) return; + RecentsTaskLoader.initialize(context); RecentsConfiguration.reinitialize(context); @@ -57,8 +70,9 @@ public class RecentsService extends Service { tsv.computeRects(windowRect.width(), windowRect.height() - systemInsets.top); tsv.boundScroll(); TaskViewTransform transform = tsv.getStackTransform(0); + Rect taskRect = new Rect(transform.rect); - data.putParcelable("taskRect", transform.rect); + data.putParcelable("taskRect", taskRect); Message reply = Message.obtain(null, MSG_UPDATE_RECENTS_FOR_CONFIGURATION, 0, 0); reply.setData(data); msg.replyTo.send(reply); @@ -69,7 +83,7 @@ public class RecentsService extends Service { } } - Messenger mMessenger = new Messenger(new MessageHandler()); + Messenger mMessenger = new Messenger(new MessageHandler(this)); @Override public void onCreate() { @@ -100,4 +114,12 @@ public class RecentsService extends Service { Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsService|onDestroy]"); super.onDestroy(); } + + @Override + public void onTrimMemory(int level) { + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); + if (loader != null) { + loader.onTrimMemory(level); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java index c303ca7..253b8e3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsTaskLoader.java @@ -17,6 +17,7 @@ package com.android.systemui.recents; import android.app.ActivityManager; +import android.content.ComponentCallbacks2; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; @@ -82,7 +83,9 @@ class TaskResourceLoader implements Runnable { TaskResourceLoadQueue mLoadQueue; DrawableLruCache mIconCache; BitmapLruCache mThumbnailCache; + boolean mCancelled; + boolean mWaitingOnLoadQueue; /** Constructor, creates a new loading thread that loads task resources in the background */ public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache iconCache, @@ -114,6 +117,11 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|stop]"); // Mark as cancelled for the thread to pick up mCancelled = true; + // If we are waiting for the load queue for more tasks, then we can just reset the + // Context now, since nothing is using it + if (mWaitingOnLoadQueue) { + mContext = null; + } } @Override @@ -122,6 +130,8 @@ class TaskResourceLoader implements Runnable { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|run|" + Thread.currentThread().getId() + "]"); if (mCancelled) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[TaskResourceLoader|cancel|" + Thread.currentThread().getId() + "]"); // We have to unset the context here, since the background thread may be using it // when we call stop() mContext = null; @@ -140,50 +150,54 @@ class TaskResourceLoader implements Runnable { final Task t = mLoadQueue.nextTask(); if (t != null) { try { - Drawable cachedIcon = mIconCache.get(t); - Bitmap cachedThumbnail = mThumbnailCache.get(t); + Drawable loadIcon = mIconCache.get(t.key); + Bitmap loadThumbnail = mThumbnailCache.get(t.key); Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoader|load]", - t + " icon: " + cachedIcon + " thumbnail: " + cachedThumbnail); + t + " icon: " + loadIcon + " thumbnail: " + loadThumbnail); // Load the icon - if (cachedIcon == null) { + if (loadIcon == null) { PackageManager pm = mContext.getPackageManager(); - ActivityInfo info = pm.getActivityInfo(t.intent.getComponent(), + ActivityInfo info = pm.getActivityInfo(t.key.intent.getComponent(), PackageManager.GET_META_DATA); Drawable icon = info.loadIcon(pm); if (!mCancelled) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - " [TaskResourceLoader|loadIcon]", - icon); - t.icon = icon; - mIconCache.put(t, icon); + if (icon != null) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + " [TaskResourceLoader|loadIcon]", + icon); + loadIcon = icon; + mIconCache.put(t.key, icon); + } } } // Load the thumbnail - if (cachedThumbnail == null) { + if (loadThumbnail == null) { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - Bitmap thumbnail = am.getTaskTopThumbnail(t.id); + Bitmap thumbnail = am.getTaskTopThumbnail(t.key.id); if (!mCancelled) { if (thumbnail != null) { Console.log(Constants.DebugFlags.App.TaskDataLoader, " [TaskResourceLoader|loadThumbnail]", thumbnail); - t.thumbnail = thumbnail; - mThumbnailCache.put(t, thumbnail); + loadThumbnail = thumbnail; + mThumbnailCache.put(t.key, thumbnail); } else { Console.logError(mContext, "Failed to load task top thumbnail for: " + - t.intent.getComponent().getPackageName()); + t.key.intent.getComponent().getPackageName()); } } } if (!mCancelled) { // Notify that the task data has changed + final Drawable newIcon = loadIcon; + final Bitmap newThumbnail = loadThumbnail; mMainThreadHandler.post(new Runnable() { @Override public void run() { - t.notifyTaskDataChanged(); + t.notifyTaskDataLoaded(newThumbnail, newIcon); } }); } @@ -198,7 +212,9 @@ class TaskResourceLoader implements Runnable { try { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[TaskResourceLoader|waitOnLoadQueue]"); + mWaitingOnLoadQueue = true; mLoadQueue.wait(); + mWaitingOnLoadQueue = false; } catch (InterruptedException ie) { ie.printStackTrace(); } @@ -209,14 +225,17 @@ class TaskResourceLoader implements Runnable { } } -/** The drawable cache */ -class DrawableLruCache extends LruCache<Task, Drawable> { +/** + * The drawable cache. By using the Task's key, we can prevent holding onto a reference to the Task + * resource data, while keeping the cache data in memory where necessary. + */ +class DrawableLruCache extends LruCache<Task.TaskKey, Drawable> { public DrawableLruCache(int cacheSize) { super(cacheSize); } @Override - protected int sizeOf(Task t, Drawable d) { + protected int sizeOf(Task.TaskKey t, Drawable d) { // The cache size will be measured in kilobytes rather than number of items // NOTE: this isn't actually correct, as the icon may be smaller int maxBytes = (d.getIntrinsicWidth() * d.getIntrinsicHeight() * 4); @@ -224,16 +243,19 @@ class DrawableLruCache extends LruCache<Task, Drawable> { } } -/** The bitmap cache */ -class BitmapLruCache extends LruCache<Task, Bitmap> { +/** + * The bitmap cache. By using the Task's key, we can prevent holding onto a reference to the Task + * resource data, while keeping the cache data in memory where necessary. + */ +class BitmapLruCache extends LruCache<Task.TaskKey, Bitmap> { public BitmapLruCache(int cacheSize) { super(cacheSize); } @Override - protected int sizeOf(Task t, Bitmap bitmap) { + protected int sizeOf(Task.TaskKey t, Bitmap bitmap) { // The cache size will be measured in kilobytes rather than number of items - return bitmap.getByteCount() / 1024; + return bitmap.getAllocationByteCount() / 1024; } } @@ -247,17 +269,30 @@ public class RecentsTaskLoader { TaskResourceLoadQueue mLoadQueue; TaskResourceLoader mLoader; + int mMaxThumbnailCacheSize; + int mMaxIconCacheSize; + BitmapDrawable mDefaultIcon; Bitmap mDefaultThumbnail; /** Private Constructor */ private RecentsTaskLoader(Context context) { + // Calculate the cache sizes, we just use a reasonable number here similar to those + // suggested in the Android docs, 1/8th for the thumbnail cache and 1/32 of the max memory + // for icons. int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - int iconCacheSize = Constants.DebugFlags.App.ForceDisableBackgroundCache ? 1 : maxMemory / 16; - int thumbnailCacheSize = Constants.DebugFlags.App.ForceDisableBackgroundCache ? 1 : maxMemory / 8; - Console.log(Constants.DebugFlags.App.SystemUIHandshake, + mMaxThumbnailCacheSize = maxMemory / 8; + mMaxIconCacheSize = mMaxThumbnailCacheSize / 4; + int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 : + mMaxIconCacheSize; + int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 : + mMaxThumbnailCacheSize; + + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|init]", "thumbnailCache: " + thumbnailCacheSize + " iconCache: " + iconCacheSize); + + // Initialize the cache and loaders mLoadQueue = new TaskResourceLoadQueue(); mIconCache = new DrawableLruCache(iconCacheSize); mThumbnailCache = new BitmapLruCache(thumbnailCacheSize); @@ -293,7 +328,7 @@ public class RecentsTaskLoader { /** Reload the set of recent tasks */ SpaceNode reload(Context context, int preloadCount) { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsTaskLoader|reload]"); + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|reload]"); TaskStack stack = new TaskStack(context); SpaceNode root = new SpaceNode(context); root.setStack(stack); @@ -310,7 +345,7 @@ public class RecentsTaskLoader { Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getRecentTasks]", "" + (System.currentTimeMillis() - t1) + "ms"); - Console.log(Constants.DebugFlags.App.SystemUIHandshake, + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|tasks]", "" + tasks.size()); // Remove home/recents tasks @@ -335,49 +370,61 @@ public class RecentsTaskLoader { int taskCount = tasks.size(); for (int i = 0; i < taskCount; i++) { ActivityManager.RecentTaskInfo t = tasks.get(i); - - // Load the label, icon and thumbnail ActivityInfo info = pm.getActivityInfo(t.baseIntent.getComponent(), PackageManager.GET_META_DATA); String title = info.loadLabel(pm).toString(); - Drawable icon = null; - Bitmap thumbnail = null; - Task task; - if (i >= (taskCount - preloadCount) || !Constants.DebugFlags.App.EnableBackgroundTaskLoading) { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, + boolean isForemostTask = (i == (taskCount - 1)); + + // Preload the specified number of apps + if (i >= (taskCount - preloadCount)) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|preloadTask]", "i: " + i + " task: " + t.baseIntent.getComponent().getPackageName()); - icon = info.loadIcon(pm); - thumbnail = am.getTaskTopThumbnail(t.id); + + Task task = new Task(t.persistentId, t.baseIntent, title); + + // Load the icon (if possible and not the foremost task, from the cache) + if (!isForemostTask) { + task.icon = mIconCache.get(task.key); + } + if (task.icon == null) { + task.icon = info.loadIcon(pm); + if (task.icon != null) { + mIconCache.put(task.key, task.icon); + } else { + task.icon = mDefaultIcon; + } + } + + // Load the thumbnail (if possible and not the foremost task, from the cache) + if (!isForemostTask) { + task.thumbnail = mThumbnailCache.get(task.key); + } + if (task.thumbnail == null) { + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[RecentsTaskLoader|loadingTaskThumbnail]"); + task.thumbnail = am.getTaskTopThumbnail(t.id); + if (task.thumbnail != null) { + mThumbnailCache.put(task.key, task.thumbnail); + } else { + task.thumbnail = mDefaultThumbnail; + } + } + + // Create as many tasks a we want to multiply by for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, + Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); - task = new Task(t.persistentId, t.baseIntent, title, icon, thumbnail); - if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) { - if (thumbnail != null) mThumbnailCache.put(task, thumbnail); - if (icon != null) { - mIconCache.put(task, icon); - } - } stack.addTask(task); } } else { + // Create as many tasks a we want to multiply by for (int j = 0; j < Constants.Values.RecentsTaskLoader.TaskEntryMultiplier; j++) { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, + Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|task]", t.baseIntent.getComponent().getPackageName()); - task = new Task(t.persistentId, t.baseIntent, title, null, null); - stack.addTask(task); + stack.addTask(new Task(t.persistentId, t.baseIntent, title)); } } - - /* - if (stacks.containsKey(t.stackId)) { - builder = stacks.get(t.stackId); - } else { - builder = new TaskStackBuilder(); - stacks.put(t.stackId, builder); - } - */ } Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllTaskTopThumbnail]", @@ -388,9 +435,9 @@ public class RecentsTaskLoader { t1 = System.currentTimeMillis(); List<ActivityManager.StackInfo> stackInfos = ams.getAllStackInfos(); Console.log(Constants.DebugFlags.App.TimeSystemCalls, "[RecentsTaskLoader|getAllStackInfos]", "" + (System.currentTimeMillis() - t1) + "ms"); - Console.log(Constants.DebugFlags.App.SystemUIHandshake, "[RecentsTaskLoader|stacks]", "" + tasks.size()); + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stacks]", "" + tasks.size()); for (ActivityManager.StackInfo s : stackInfos) { - Console.log(Constants.DebugFlags.App.SystemUIHandshake, " [RecentsTaskLoader|stack]", s.toString()); + Console.log(Constants.DebugFlags.App.TaskDataLoader, " [RecentsTaskLoader|stack]", s.toString()); if (stacks.containsKey(s.stackId)) { stacks.get(s.stackId).setRect(s.bounds); } @@ -399,65 +446,93 @@ public class RecentsTaskLoader { } catch (Exception e) { e.printStackTrace(); } + + // Start the task loader mLoader.start(context); + return root; } - /** Acquires the task resource data from the pool. - * XXX: Move this into Task? */ + /** Acquires the task resource data from the pool. */ public void loadTaskData(Task t) { - if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) { - t.icon = mIconCache.get(t); - t.thumbnail = mThumbnailCache.get(t); + Drawable icon = mIconCache.get(t.key); + Bitmap thumbnail = mThumbnailCache.get(t.key); - Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]", - t + " icon: " + t.icon + " thumbnail: " + t.thumbnail); + Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|loadTask]", + t + " icon: " + icon + " thumbnail: " + thumbnail + + " thumbnailCacheSize: " + mThumbnailCache.size()); - boolean requiresLoad = false; - if (t.icon == null) { - t.icon = mDefaultIcon; - requiresLoad = true; - } - if (t.thumbnail == null) { - t.thumbnail = mDefaultThumbnail; - requiresLoad = true; - } - if (requiresLoad) { - mLoadQueue.addTask(t); - } + boolean requiresLoad = false; + if (icon == null) { + icon = mDefaultIcon; + requiresLoad = true; + } + if (thumbnail == null) { + thumbnail = mDefaultThumbnail; + requiresLoad = true; } + if (requiresLoad) { + mLoadQueue.addTask(t); + } + t.notifyTaskDataLoaded(thumbnail, icon); } - /** Releases the task resource data back into the pool. - * XXX: Move this into Task? */ + /** Releases the task resource data back into the pool. */ public void unloadTaskData(Task t) { - if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - "[RecentsTaskLoader|unloadTask]", t); - mLoadQueue.removeTask(t); - t.icon = mDefaultIcon; - t.thumbnail = mDefaultThumbnail; - } + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[RecentsTaskLoader|unloadTask]", t + + " thumbnailCacheSize: " + mThumbnailCache.size()); + + mLoadQueue.removeTask(t); + t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultIcon); } - /** Completely removes the resource data from the pool. - * XXX: Move this into Task? */ + /** Completely removes the resource data from the pool. */ public void deleteTaskData(Task t) { - if (Constants.DebugFlags.App.EnableBackgroundTaskLoading) { - Console.log(Constants.DebugFlags.App.TaskDataLoader, - "[RecentsTaskLoader|deleteTask]", t); - mLoadQueue.removeTask(t); - mThumbnailCache.remove(t); - mIconCache.remove(t); - } - t.icon = mDefaultIcon; - t.thumbnail = mDefaultThumbnail; + Console.log(Constants.DebugFlags.App.TaskDataLoader, + "[RecentsTaskLoader|deleteTask]", t); + + mLoadQueue.removeTask(t); + mThumbnailCache.remove(t.key); + mIconCache.remove(t.key); + t.notifyTaskDataUnloaded(mDefaultThumbnail, mDefaultIcon); } - /** Stops the task loader */ + /** Stops the task loader and clears all pending tasks */ void stopLoader() { Console.log(Constants.DebugFlags.App.TaskDataLoader, "[RecentsTaskLoader|stopLoader]"); mLoader.stop(); mLoadQueue.clearTasks(); } + + void onTrimMemory(int level) { + Console.log(Constants.DebugFlags.App.Memory, "[RecentsTaskLoader|onTrimMemory]", + Console.trimMemoryLevelToString(level)); + + switch (level) { + case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN: + // Do nothing + break; + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE: + case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND: + // We are leaving recents, so trim the data a bit + mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 2); + mIconCache.trimToSize(mMaxIconCacheSize / 2); + break; + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW: + case ComponentCallbacks2.TRIM_MEMORY_MODERATE: + // We are going to be low on memory + mThumbnailCache.trimToSize(mMaxThumbnailCacheSize / 4); + mIconCache.trimToSize(mMaxIconCacheSize / 4); + break; + case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL: + case ComponentCallbacks2.TRIM_MEMORY_COMPLETE: + // We are low on memory, so release everything + mThumbnailCache.evictAll(); + mIconCache.evictAll(); + break; + default: + break; + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java index 5893abc..1dd1be6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNode.java @@ -17,6 +17,7 @@ package com.android.systemui.recents.model; import android.content.Context; +import android.graphics.Rect; import java.util.ArrayList; @@ -26,6 +27,14 @@ import java.util.ArrayList; * stacks should be placed. */ public class SpaceNode { + /* BSP node callbacks */ + public interface SpaceNodeCallbacks { + /** Notifies when a node is added */ + public void onSpaceNodeAdded(SpaceNode node); + /** Notifies when a node is measured */ + public void onSpaceNodeMeasured(SpaceNode node, Rect rect); + } + Context mContext; SpaceNode mStartNode; diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNodeCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNodeCallbacks.java deleted file mode 100644 index 31b02e7..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/model/SpaceNodeCallbacks.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents.model; - -import android.graphics.Rect; - - -/* BSP node callbacks */ -public interface SpaceNodeCallbacks { - /** Notifies when a node is added */ - public void onSpaceNodeAdded(SpaceNode node); - /** Notifies when a node is measured */ - public void onSpaceNodeMeasured(SpaceNode node, Rect rect); -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 9b03c5d..0c3c528 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -26,17 +26,53 @@ import com.android.systemui.recents.Constants; * A task represents the top most task in the system's task stack. */ public class Task { - public final int id; - public final Intent intent; + /* Task callbacks */ + public interface TaskCallbacks { + /* Notifies when a task has been bound */ + public void onTaskDataLoaded(); + /* Notifies when a task has been unbound */ + public void onTaskDataUnloaded(); + } + + /* The Task Key represents the unique primary key for the task */ + public static class TaskKey { + public final int id; + public final Intent intent; + + public TaskKey(int id, Intent intent) { + this.id = id; + this.intent = intent; + } + + @Override + public boolean equals(Object o) { + return hashCode() == o.hashCode(); + } + + @Override + public int hashCode() { + return id; + } + + @Override + public String toString() { + return "Task.Key: " + id + ", " + intent.getComponent().getPackageName(); + } + } + + public TaskKey key; public String title; public Drawable icon; public Bitmap thumbnail; TaskCallbacks mCb; + public Task(int id, Intent intent, String activityTitle) { + this(id, intent, activityTitle, null, null); + } + public Task(int id, Intent intent, String activityTitle, Drawable icon, Bitmap thumbnail) { - this.id = id; - this.intent = intent; + this.key = new TaskKey(id, intent); this.title = activityTitle; this.icon = icon; this.thumbnail = thumbnail; @@ -47,10 +83,21 @@ public class Task { mCb = cb; } - /** Notifies the callback listeners that this task's data has changed */ - public void notifyTaskDataChanged() { + /** Notifies the callback listeners that this task has been loaded */ + public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable icon) { + this.icon = icon; + this.thumbnail = thumbnail; + if (mCb != null) { + mCb.onTaskDataLoaded(); + } + } + + /** Notifies the callback listeners that this task has been unloaded */ + public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultIcon) { + icon = defaultIcon; + thumbnail = defaultThumbnail; if (mCb != null) { - mCb.onTaskDataChanged(this); + mCb.onTaskDataUnloaded(); } } @@ -65,12 +112,11 @@ public class Task { // Otherwise, check that the id and intent match (the other fields can be asynchronously // loaded and is unsuitable to testing the identity of this Task) Task t = (Task) o; - return (id == t.id) && - (intent.equals(t.intent)); + return key.equals(t.key); } @Override public String toString() { - return "Task: " + intent.getComponent().getPackageName() + " [" + super.toString() + "]"; + return "Task: " + key.intent.getComponent().getPackageName() + " [" + super.toString() + "]"; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java deleted file mode 100644 index 169f56c..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskCallbacks.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents.model; - -/* Task callbacks */ -public interface TaskCallbacks { - /* Notifies when a task's data has been updated */ - public void onTaskDataChanged(Task task); -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index a5aa387..f2f89ae 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -119,6 +119,18 @@ class FilteredTaskList { * The task stack contains a list of multiple tasks. */ public class TaskStack { + /* Task stack callbacks */ + public interface TaskStackCallbacks { + /* Notifies when a task has been added to the stack */ + public void onStackTaskAdded(TaskStack stack, Task t); + /* Notifies when a task has been removed from the stack */ + public void onStackTaskRemoved(TaskStack stack, Task t); + /** Notifies when the stack was filtered */ + public void onStackFiltered(TaskStack stack); + /** Notifies when the stack was un-filtered */ + public void onStackUnfiltered(TaskStack stack); + } + Context mContext; FilteredTaskList mTaskList = new FilteredTaskList(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStackCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStackCallbacks.java deleted file mode 100644 index 4bec655..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStackCallbacks.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents.model; - -/* Task stack callbacks */ -public interface TaskStackCallbacks { - /* Notifies when a task has been added to the stack */ - public void onStackTaskAdded(TaskStack stack, Task t); - /* Notifies when a task has been removed from the stack */ - public void onStackTaskRemoved(TaskStack stack, Task t); - /** Notifies when the stack was filtered */ - public void onStackFiltered(TaskStack stack); - /** Notifies when the stack was un-filtered */ - public void onStackUnfiltered(TaskStack stack); -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index c92041c..c85c14b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -39,7 +39,7 @@ import java.util.ArrayList; * This view is the the top level layout that contains TaskStacks (which are laid out according * to their SpaceNode bounds. */ -public class RecentsView extends FrameLayout implements TaskStackViewCallbacks { +public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks { // The space partitioning root of this container SpaceNode mBSP; @@ -52,8 +52,7 @@ public class RecentsView extends FrameLayout implements TaskStackViewCallbacks { public void setBSP(SpaceNode n) { mBSP = n; - // XXX: We shouldn't be recereating new stacks every time, but for now, that is OK - // Add all the stacks for this partition + // Create and add all the stacks for this partition of space. removeAllViews(); ArrayList<TaskStack> stacks = mBSP.getStacks(); for (TaskStack stack : stacks) { @@ -91,7 +90,8 @@ public class RecentsView extends FrameLayout implements TaskStackViewCallbacks { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); - Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]", "width: " + width + " height: " + height, Console.AnsiGreen); + Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|measure]", + "width: " + width + " height: " + height, Console.AnsiGreen); // We measure our stack views sans the status bar. It will handle the nav bar itself. RecentsConfiguration config = RecentsConfiguration.getInstance(); @@ -112,7 +112,8 @@ public class RecentsView extends FrameLayout implements TaskStackViewCallbacks { @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]", new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen); + Console.log(Constants.DebugFlags.UI.MeasureAndLayout, "[RecentsView|layout]", + new Rect(left, top, right, bottom) + " changed: " + changed, Console.AnsiGreen); // We offset our stack views by the status bar height. It will handle the nav bar itself. RecentsConfiguration config = RecentsConfiguration.getInstance(); top += config.systemInsets.top; @@ -206,7 +207,7 @@ public class RecentsView extends FrameLayout implements TaskStackViewCallbacks { } // Launch the activity with the desired animation - Intent i = new Intent(task.intent); + Intent i = new Intent(task.key.intent); i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY | Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_TASK); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java index fe661bc..21ef9ff 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java @@ -28,6 +28,8 @@ import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.animation.LinearInterpolator; +import com.android.systemui.recents.Console; +import com.android.systemui.recents.Constants; /** * This class facilitates swipe to dismiss. It defines an interface to be implemented by the @@ -176,6 +178,9 @@ public class SwipeHelper { } public boolean onInterceptTouchEvent(MotionEvent ev) { + Console.log(Constants.DebugFlags.UI.TouchEvents, + "[SwipeHelper|interceptTouchEvent]", + Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); final int action = ev.getAction(); switch (action) { @@ -200,7 +205,7 @@ public class SwipeHelper { if (Math.abs(delta) > mPagingTouchSlop) { mCallback.onBeginDrag(mCurrView); mDragging = true; - mInitialTouchPos = getPos(ev) - getTranslation(mCurrView); + mInitialTouchPos = pos - getTranslation(mCurrView); } } break; @@ -286,6 +291,10 @@ public class SwipeHelper { } public boolean onTouchEvent(MotionEvent ev) { + Console.log(Constants.DebugFlags.UI.TouchEvents, + "[SwipeHelper|touchEvent]", + Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); + if (!mDragging) { if (!onInterceptTouchEvent(ev)) { return mCanCurrViewBeDimissed; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 9dd6c0b..17660d8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -33,7 +33,6 @@ import android.view.ViewConfiguration; import android.view.ViewParent; import android.widget.FrameLayout; import android.widget.OverScroller; -import android.widget.Toast; import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; @@ -41,18 +40,20 @@ import com.android.systemui.recents.RecentsTaskLoader; import com.android.systemui.recents.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; -import com.android.systemui.recents.model.TaskStackCallbacks; import java.util.ArrayList; -/** The TaskView callbacks */ -interface TaskStackViewCallbacks { - public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t); -} /* The visual representation of a task stack view */ -public class TaskStackView extends FrameLayout implements TaskStackCallbacks, TaskViewCallbacks, - ViewPoolConsumer<TaskView, Task>, View.OnClickListener { +public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks, + TaskView.TaskViewCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task>, + View.OnClickListener { + + /** The TaskView callbacks */ + interface TaskStackViewCallbacks { + public void onTaskLaunched(TaskStackView stackView, TaskView tv, TaskStack stack, Task t); + } + TaskStack mStack; TaskStackViewTouchHandler mTouchHandler; TaskStackViewCallbacks mCb; @@ -242,10 +243,10 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta int newScroll = Math.max(mMinScroll, Math.min(mMaxScroll, curScroll)); if (newScroll != curScroll) { // Enable hw layers on the stack - addHwLayersRefCount(); + addHwLayersRefCount("animateBoundScroll"); // Abort any current animations - mScroller.abortAnimation(); + abortScroller(); if (mScrollAnimator != null) { mScrollAnimator.cancel(); mScrollAnimator.removeAllListeners(); @@ -264,7 +265,7 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta @Override public void onAnimationEnd(Animator animation) { // Disable hw layers on the stack - decHwLayersRefCount(); + decHwLayersRefCount("animateBoundScroll"); } }); mScrollAnimator.start(); @@ -279,6 +280,15 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta } } + void abortScroller() { + if (!mScroller.isFinished()) { + // Abort the scroller + mScroller.abortAnimation(); + // And disable hw layers on the stack + decHwLayersRefCount("flingScroll"); + } + } + /** Bounds the current scroll if necessary */ public boolean boundScroll() { int curScroll = getStackScroll(); @@ -318,10 +328,10 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta } /** Enables the hw layers and increments the hw layer requirement ref count */ - void addHwLayersRefCount() { + void addHwLayersRefCount(String reason) { Console.log(Constants.DebugFlags.UI.HwLayers, "[TaskStackView|addHwLayersRefCount] refCount: " + - mHwLayersRefCount + "->" + (mHwLayersRefCount + 1)); + mHwLayersRefCount + "->" + (mHwLayersRefCount + 1) + " " + reason); if (mHwLayersRefCount == 0) { // Enable hw layers on each of the children int childCount = getChildCount(); @@ -335,10 +345,10 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta /** Decrements the hw layer requirement ref count and disables the hw layers when we don't need them anymore. */ - void decHwLayersRefCount() { + void decHwLayersRefCount(String reason) { Console.log(Constants.DebugFlags.UI.HwLayers, "[TaskStackView|decHwLayersRefCount] refCount: " + - mHwLayersRefCount + "->" + (mHwLayersRefCount - 1)); + mHwLayersRefCount + "->" + (mHwLayersRefCount - 1) + " " + reason); mHwLayersRefCount--; if (mHwLayersRefCount == 0) { // Disable hw layers on each of the children @@ -348,7 +358,8 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta tv.disableHwLayers(); } } else if (mHwLayersRefCount < 0) { - throw new RuntimeException("Invalid hw layers ref count"); + new Throwable("Invalid hw layers ref count").printStackTrace(); + Console.logError(getContext(), "Invalid HW layers ref count"); } } @@ -360,7 +371,7 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta // If we just finished scrolling, then disable the hw layers if (mScroller.isFinished()) { - decHwLayersRefCount(); + decHwLayersRefCount("finishedFlingScroll"); } } } @@ -435,19 +446,12 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta mStackRectSansPeek.top += Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height(); // Compute the task rect - if (RecentsConfiguration.getInstance().layoutVerticalStack) { - int minHeight = (int) (mStackRect.height() - - (Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height())); - int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height())); - int centerX = mStackRect.centerX(); - mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top, - centerX + size / 2, mStackRectSansPeek.top + size); - } else { - int size = Math.min(mStackRect.width(), mStackRect.height()); - int centerY = mStackRect.centerY(); - mTaskRect.set(mStackRectSansPeek.top, centerY - size / 2, - mStackRectSansPeek.top + size, centerY + size / 2); - } + int minHeight = (int) (mStackRect.height() - + (Constants.Values.TaskStackView.StackPeekHeightPct * mStackRect.height())); + int size = Math.min(minHeight, Math.min(mStackRect.width(), mStackRect.height())); + int centerX = mStackRect.centerX(); + mTaskRect.set(centerX - size / 2, mStackRectSansPeek.top, + centerX + size / 2, mStackRectSansPeek.top + size); // Update the scroll bounds updateMinMaxScroll(false); @@ -589,7 +593,6 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta // Report that this tasks's data is no longer being used RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); loader.unloadTaskData(task); - tv.unbindFromTask(); // Detach the view from the hierarchy detachViewFromParent(tv); @@ -606,11 +609,10 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta // Setup and attach the view to the window Task task = prepareData; // We try and rebind the task (this MUST be done before the task filled) - tv.bindToTask(task, this); + tv.onTaskBound(task); // Request that this tasks's data be filled RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); loader.loadTaskData(task); - tv.syncToTask(); // Find the index where this task should be placed in the children int insertIndex = -1; @@ -628,7 +630,10 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta "" + insertIndex); if (isNewView) { addView(tv, insertIndex); + + // Set the callbacks and listeners for this new view tv.setOnClickListener(this); + tv.setCallbacks(this); } else { attachViewToParent(tv, insertIndex, tv.getLayoutParams()); } @@ -658,7 +663,7 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta mStack.filterTasks(tv.getTask()); } } else { - Toast.makeText(getContext(), "Task Filtering TBD", Toast.LENGTH_SHORT).show(); + Console.logError(getContext(), "Task Filtering TBD"); } } @@ -678,14 +683,13 @@ public class TaskStackView extends FrameLayout implements TaskStackCallbacks, Ta } /* Handles touch events */ -class TaskStackViewTouchHandler { +class TaskStackViewTouchHandler implements SwipeHelper.Callback { static int INACTIVE_POINTER_ID = -1; TaskStackView mSv; VelocityTracker mVelocityTracker; boolean mIsScrolling; - boolean mIsSwiping; int mInitialMotionX, mInitialMotionY; int mLastMotionX, mLastMotionY; @@ -697,21 +701,24 @@ class TaskStackViewTouchHandler { int mMaximumVelocity; // The scroll touch slop is used to calculate when we start scrolling int mScrollTouchSlop; - // The swipe touch slop is used to calculate when we start swiping left/right, this takes - // precendence over the scroll touch slop in case the user makes a gesture that starts scrolling - // but is intended to be a swipe - int mSwipeTouchSlop; - // After a certain amount of scrolling, we should start ignoring checks for swiping - int mMaxScrollMotionToRejectSwipe; + // The page touch slop is used to calculate when we start swiping + float mPagingTouchSlop; + + SwipeHelper mSwipeHelper; + boolean mInterceptedBySwipeHelper; public TaskStackViewTouchHandler(Context context, TaskStackView sv) { ViewConfiguration configuration = ViewConfiguration.get(context); mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); mScrollTouchSlop = configuration.getScaledTouchSlop(); - mSwipeTouchSlop = 2 * mScrollTouchSlop; - mMaxScrollMotionToRejectSwipe = 4 * mScrollTouchSlop; + mPagingTouchSlop = configuration.getScaledPagingTouchSlop(); mSv = sv; + + + float densityScale = context.getResources().getDisplayMetrics().density; + mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop); + mSwipeHelper.setMinAlpha(1f); } /** Velocity tracker helpers */ @@ -754,11 +761,18 @@ class TaskStackViewTouchHandler { "[TaskStackViewTouchHandler|interceptTouchEvent]", Console.motionEventActionToString(ev.getAction()), Console.AnsiBlue); + // Return early if we have no children boolean hasChildren = (mSv.getChildCount() > 0); if (!hasChildren) { return false; } + // Pass through to swipe helper if we are swiping + mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev); + if (mInterceptedBySwipeHelper) { + return true; + } + boolean wasScrolling = !mSv.mScroller.isFinished() || (mSv.mScrollAnimator != null && mSv.mScrollAnimator.isRunning()); int action = ev.getAction(); @@ -770,14 +784,13 @@ class TaskStackViewTouchHandler { mActivePointerId = ev.getPointerId(0); mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY); // Stop the current scroll if it is still flinging - mSv.mScroller.abortAnimation(); + mSv.abortScroller(); mSv.abortBoundScrollAnimation(); // Initialize the velocity tracker initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); // Check if the scroller is finished yet mIsScrolling = !mSv.mScroller.isFinished(); - mIsSwiping = false; break; } case MotionEvent.ACTION_MOVE: { @@ -786,25 +799,7 @@ class TaskStackViewTouchHandler { int activePointerIndex = ev.findPointerIndex(mActivePointerId); int y = (int) ev.getY(activePointerIndex); int x = (int) ev.getX(activePointerIndex); - if (mActiveTaskView != null && - mTotalScrollMotion < mMaxScrollMotionToRejectSwipe && - Math.abs(x - mInitialMotionX) > Math.abs(y - mInitialMotionY) && - Math.abs(x - mInitialMotionX) > mSwipeTouchSlop) { - // Start swiping and stop scrolling - mIsScrolling = false; - mIsSwiping = true; - System.out.println("SWIPING: " + mActiveTaskView); - // Initialize the velocity tracker if necessary - initOrResetVelocityTracker(); - mVelocityTracker.addMovement(ev); - // Disallow parents from intercepting touch events - final ViewParent parent = mSv.getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - // Enable HW layers - mSv.addHwLayersRefCount(); - } else if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) { + if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) { // Save the touch move info mIsScrolling = true; // Initialize the velocity tracker if necessary @@ -816,7 +811,7 @@ class TaskStackViewTouchHandler { parent.requestDisallowInterceptTouchEvent(true); } // Enable HW layers - mSv.addHwLayersRefCount(); + mSv.addHwLayersRefCount("stackScroll"); } mLastMotionX = x; @@ -827,9 +822,12 @@ class TaskStackViewTouchHandler { case MotionEvent.ACTION_UP: { // Animate the scroll back if we've cancelled mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); + // Disable HW layers + if (mIsScrolling) { + mSv.decHwLayersRefCount("stackScroll"); + } // Reset the drag state and the velocity tracker mIsScrolling = false; - mIsSwiping = false; mActivePointerId = INACTIVE_POINTER_ID; mActiveTaskView = null; mTotalScrollMotion = 0; @@ -838,7 +836,7 @@ class TaskStackViewTouchHandler { } } - return wasScrolling || mIsScrolling || mIsSwiping; + return wasScrolling || mIsScrolling; } /** Handles touch events once we have intercepted them */ @@ -853,6 +851,11 @@ class TaskStackViewTouchHandler { return false; } + // Pass through to swipe helper if we are swiping + if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) { + return true; + } + // Update the velocity tracker initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); @@ -866,12 +869,11 @@ class TaskStackViewTouchHandler { mActivePointerId = ev.getPointerId(0); mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY); // Stop the current scroll if it is still flinging - mSv.mScroller.abortAnimation(); + mSv.abortScroller(); mSv.abortBoundScrollAnimation(); // Initialize the velocity tracker initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); - // XXX: Set mIsScrolling or mIsSwiping? // Disallow parents from intercepting touch events final ViewParent parent = mSv.getParent(); if (parent != null) { @@ -886,28 +888,7 @@ class TaskStackViewTouchHandler { int x = (int) ev.getX(activePointerIndex); int y = (int) ev.getY(activePointerIndex); int deltaY = mLastMotionY - y; - int deltaX = x - mLastMotionX; - if (!mIsSwiping) { - if (mActiveTaskView != null && - mTotalScrollMotion < mMaxScrollMotionToRejectSwipe && - Math.abs(x - mInitialMotionX) > Math.abs(y - mInitialMotionY) && - Math.abs(x - mInitialMotionX) > mSwipeTouchSlop) { - mIsScrolling = false; - mIsSwiping = true; - System.out.println("SWIPING: " + mActiveTaskView); - // Initialize the velocity tracker if necessary - initOrResetVelocityTracker(); - mVelocityTracker.addMovement(ev); - // Disallow parents from intercepting touch events - final ViewParent parent = mSv.getParent(); - if (parent != null) { - parent.requestDisallowInterceptTouchEvent(true); - } - // Enable HW layers - mSv.addHwLayersRefCount(); - } - } - if (!mIsSwiping && !mIsScrolling) { + if (!mIsScrolling) { if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) { mIsScrolling = true; // Initialize the velocity tracker @@ -919,7 +900,7 @@ class TaskStackViewTouchHandler { parent.requestDisallowInterceptTouchEvent(true); } // Enable HW layers - mSv.addHwLayersRefCount(); + mSv.addHwLayersRefCount("stackScroll"); } } if (mIsScrolling) { @@ -927,8 +908,6 @@ class TaskStackViewTouchHandler { if (mSv.isScrollOutOfBounds()) { mVelocityTracker.clear(); } - } else if (mIsSwiping) { - mActiveTaskView.setTranslationX(mActiveTaskView.getTranslationX() + deltaX); } mLastMotionX = x; mLastMotionY = y; @@ -936,140 +915,126 @@ class TaskStackViewTouchHandler { break; } case MotionEvent.ACTION_UP: { - if (mIsScrolling || mIsSwiping) { - final TaskView activeTv = mActiveTaskView; - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - - if (mIsSwiping) { - int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId); - if ((Math.abs(initialVelocity) > mMinimumVelocity)) { - // Fling to dismiss - int newScrollX = (int) (Math.signum(initialVelocity) * - activeTv.getMeasuredWidth()); - int duration = Math.min(Constants.Values.TaskStackView.Animation.SwipeDismissDuration, - (int) (Math.abs(newScrollX - activeTv.getScrollX()) * - 1000f / Math.abs(initialVelocity))); - activeTv.animate() - .translationX(newScrollX) - .alpha(0f) - .setDuration(duration) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - Task task = activeTv.getTask(); - Activity activity = (Activity) mSv.getContext(); - - // We have to disable the listener to ensure that we - // don't hit this again - activeTv.animate().setListener(null); - - // Remove the task from the view - mSv.mStack.removeTask(task); - - // Remove any stored data from the loader - RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); - loader.deleteTaskData(task); - - // Remove the task from activity manager - final ActivityManager am = (ActivityManager) - activity.getSystemService(Context.ACTIVITY_SERVICE); - if (am != null) { - am.removeTask(activeTv.getTask().id, - ActivityManager.REMOVE_TASK_KILL_PROCESS); - } - - // If there are no remaining tasks, then just close the activity - if (mSv.mStack.getTaskCount() == 0) { - activity.finish(); - } - - // Disable HW layers - mSv.decHwLayersRefCount(); - } - }) - .start(); - // Enable HW layers - mSv.addHwLayersRefCount(); - } else { - // Animate it back into place - // XXX: Make this animation a function of the velocity OR distance - int duration = Constants.Values.TaskStackView.Animation.SwipeSnapBackDuration; - activeTv.animate() - .translationX(0) - .setDuration(duration) - .setListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - // Disable HW layers - mSv.decHwLayersRefCount(); - } - }) - .start(); - // Enable HW layers - mSv.addHwLayersRefCount(); - } - } else { - int velocity = (int) velocityTracker.getYVelocity(mActivePointerId); - if ((Math.abs(velocity) > mMinimumVelocity)) { - Console.log(Constants.DebugFlags.UI.TouchEvents, - "[TaskStackViewTouchHandler|fling]", - "scroll: " + mSv.getStackScroll() + " velocity: " + velocity, - Console.AnsiGreen); - // Enable HW layers on the stack - mSv.addHwLayersRefCount(); - // Fling scroll - mSv.mScroller.fling(0, mSv.getStackScroll(), - 0, -velocity, - 0, 0, - mSv.mMinScroll, mSv.mMaxScroll, - 0, 0); - // Invalidate to kick off computeScroll - mSv.invalidate(); - } else if (mSv.isScrollOutOfBounds()) { - // Animate the scroll back into bounds - // XXX: Make this animation a function of the velocity OR distance - mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); - } - } + final VelocityTracker velocityTracker = mVelocityTracker; + velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); + int velocity = (int) velocityTracker.getYVelocity(mActivePointerId); + + if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) { + Console.log(Constants.DebugFlags.UI.TouchEvents, + "[TaskStackViewTouchHandler|fling]", + "scroll: " + mSv.getStackScroll() + " velocity: " + velocity, + Console.AnsiGreen); + // Enable HW layers on the stack + mSv.addHwLayersRefCount("flingScroll"); + // Fling scroll + mSv.mScroller.fling(0, mSv.getStackScroll(), + 0, -velocity, + 0, 0, + mSv.mMinScroll, mSv.mMaxScroll, + 0, 0); + // Invalidate to kick off computeScroll + mSv.invalidate(); + } else if (mSv.isScrollOutOfBounds()) { + // Animate the scroll back into bounds + // XXX: Make this animation a function of the velocity OR distance + mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); } + if (mIsScrolling) { + // Disable HW layers + mSv.decHwLayersRefCount("stackScroll"); + } mActivePointerId = INACTIVE_POINTER_ID; mIsScrolling = false; - mIsSwiping = false; mTotalScrollMotion = 0; recycleVelocityTracker(); - // Disable HW layers - mSv.decHwLayersRefCount(); break; } case MotionEvent.ACTION_CANCEL: { - if (mIsScrolling || mIsSwiping) { - if (mIsSwiping) { - // Animate it back into place - // XXX: Make this animation a function of the velocity OR distance - int duration = Constants.Values.TaskStackView.Animation.SwipeSnapBackDuration; - mActiveTaskView.animate() - .translationX(0) - .setDuration(duration) - .start(); - } else { - // Animate the scroll back into bounds - // XXX: Make this animation a function of the velocity OR distance - mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); - } + if (mIsScrolling) { + // Disable HW layers + mSv.decHwLayersRefCount("stackScroll"); + } + if (mSv.isScrollOutOfBounds()) { + // Animate the scroll back into bounds + // XXX: Make this animation a function of the velocity OR distance + mSv.animateBoundScroll(Constants.Values.TaskStackView.Animation.SnapScrollBackDuration); } - mActivePointerId = INACTIVE_POINTER_ID; mIsScrolling = false; - mIsSwiping = false; mTotalScrollMotion = 0; recycleVelocityTracker(); - // Disable HW layers - mSv.decHwLayersRefCount(); break; } } return true; } + + /**** SwipeHelper Implementation ****/ + + @Override + public View getChildAtPosition(MotionEvent ev) { + return findViewAtPoint((int) ev.getX(), (int) ev.getY()); + } + + @Override + public boolean canChildBeDismissed(View v) { + return true; + } + + @Override + public void onBeginDrag(View v) { + // Enable HW layers + mSv.addHwLayersRefCount("swipeBegin"); + // Disallow parents from intercepting touch events + final ViewParent parent = mSv.getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + } + + @Override + public void onChildDismissed(View v) { + TaskView tv = (TaskView) v; + Task task = tv.getTask(); + Activity activity = (Activity) mSv.getContext(); + + // We have to disable the listener to ensure that we + // don't hit this again + tv.animate().setListener(null); + + // Remove the task from the view + mSv.mStack.removeTask(task); + + // Remove any stored data from the loader + RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); + loader.deleteTaskData(task); + + // Remove the task from activity manager + final ActivityManager am = (ActivityManager) + activity.getSystemService(Context.ACTIVITY_SERVICE); + if (am != null) { + am.removeTask(tv.getTask().key.id, + ActivityManager.REMOVE_TASK_KILL_PROCESS); + } + + // If there are no remaining tasks, then just close the activity + if (mSv.mStack.getTaskCount() == 0) { + activity.finish(); + } + + // Disable HW layers + mSv.decHwLayersRefCount("swipeComplete"); + } + + @Override + public void onSnapBackCompleted(View v) { + // Do Nothing + } + + @Override + public void onDragCancelled(View v) { + // Disable HW layers + mSv.decHwLayersRefCount("swipeCancelled"); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index b1d0d13..ace2428 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -39,13 +39,7 @@ import com.android.systemui.recents.Console; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.model.TaskCallbacks; -/** The TaskView callbacks */ -interface TaskViewCallbacks { - public void onTaskIconClicked(TaskView tv); - // public void onTaskViewReboundToTask(TaskView tv, Task t); -} /** The task thumbnail view */ class TaskThumbnailView extends ImageView { @@ -66,7 +60,7 @@ class TaskThumbnailView extends ImageView { // Update the bar color if (Constants.Values.TaskView.DrawColoredTaskBars) { int[] colors = {0xFFCC0C39, 0xFFE6781E, 0xFFC8CF02, 0xFF1693A7}; - mBarColor = colors[mTask.intent.getComponent().getPackageName().length() % colors.length]; + mBarColor = colors[mTask.key.intent.getComponent().getPackageName().length() % colors.length]; } setImageBitmap(t.thumbnail); @@ -213,7 +207,13 @@ class TaskIconView extends ImageView { } /* A task view */ -public class TaskView extends FrameLayout implements View.OnClickListener, TaskCallbacks { +public class TaskView extends FrameLayout implements View.OnClickListener, Task.TaskCallbacks { + /** The TaskView callbacks */ + interface TaskViewCallbacks { + public void onTaskIconClicked(TaskView tv); + // public void onTaskViewReboundToTask(TaskView tv, Task t); + } + Task mTask; TaskThumbnailView mThumbnailView; TaskIconView mIconView; @@ -247,26 +247,11 @@ public class TaskView extends FrameLayout implements View.OnClickListener, TaskC ((LayoutParams) mIconView.getLayoutParams()).rightMargin = offset; } - /** Set the task and callback */ - void bindToTask(Task t, TaskViewCallbacks cb) { - mTask = t; - mTask.setCallbacks(this); + /** Set callback */ + void setCallbacks(TaskViewCallbacks cb) { mCb = cb; } - /** Actually synchronizes the model data into the views */ - void syncToTask() { - mThumbnailView.rebindToTask(mTask, false); - mIconView.rebindToTask(mTask, false); - } - - /** Unset the task and callback */ - void unbindFromTask() { - mTask.setCallbacks(null); - mThumbnailView.unbindFromTask(); - mIconView.unbindFromTask(); - } - /** Gets the task */ Task getTask() { return mTask; @@ -357,26 +342,35 @@ public class TaskView extends FrameLayout implements View.OnClickListener, TaskC /** Enable the hw layers on this task view */ void enableHwLayers() { - Console.log(Constants.DebugFlags.UI.HwLayers, "[TaskView|enableHwLayers]"); mThumbnailView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } /** Disable the hw layers on this task view */ void disableHwLayers() { - Console.log(Constants.DebugFlags.UI.HwLayers, "[TaskView|disableHwLayers]"); mThumbnailView.setLayerType(View.LAYER_TYPE_NONE, null); } + /**** TaskCallbacks Implementation ****/ + + /** Binds this task view to the task */ + public void onTaskBound(Task t) { + mTask = t; + mTask.setCallbacks(this); + } + @Override - public void onTaskDataChanged(Task task) { - Console.log(Constants.DebugFlags.App.EnableBackgroundTaskLoading, - "[TaskView|onTaskDataChanged]", task); - - // Only update this task view if the changed task is the same as the task for this view - if (mTask == task) { - mThumbnailView.rebindToTask(mTask, true); - mIconView.rebindToTask(mTask, true); - } + public void onTaskDataLoaded() { + // Bind each of the views to the new task data + mThumbnailView.rebindToTask(mTask, false); + mIconView.rebindToTask(mTask, false); + } + + @Override + public void onTaskDataUnloaded() { + // Unbind each of the views from the task data and remove the task callback + mTask.setCallbacks(null); + mThumbnailView.unbindFromTask(); + mIconView.unbindFromTask(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java index f7d7095..af0094e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java @@ -24,6 +24,15 @@ import java.util.LinkedList; /* A view pool to manage more views than we can visibly handle */ public class ViewPool<V, T> { + + /* An interface to the consumer of a view pool */ + public interface ViewPoolConsumer<V, T> { + public V createView(Context context); + public void prepareViewToEnterPool(V v); + public void prepareViewToLeavePool(V v, T prepareData, boolean isNewView); + public boolean hasPreferredData(V v, T preferredData); + } + Context mContext; ViewPoolConsumer<V, T> mViewCreator; LinkedList<V> mPool = new LinkedList<V>(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPoolConsumer.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPoolConsumer.java deleted file mode 100644 index 50f45bf..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPoolConsumer.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents.views; - -import android.content.Context; - - -/* An interface to the consumer of a view pool */ -public interface ViewPoolConsumer<V, T> { - public V createView(Context context); - public void prepareViewToEnterPool(V v); - public void prepareViewToLeavePool(V v, T prepareData, boolean isNewView); - public boolean hasPreferredData(V v, T preferredData); -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index a89921f..bd36128 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -28,6 +28,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.UserInfo; import android.content.res.ColorStateList; import android.content.res.Configuration; import android.database.ContentObserver; @@ -46,6 +47,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; @@ -55,6 +57,7 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.TextAppearanceSpan; import android.util.Log; +import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.ContextThemeWrapper; import android.view.Display; @@ -140,6 +143,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected PopupMenu mNotificationBlamePopup; protected int mCurrentUserId = 0; + final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>(); protected int mLayoutDirection = -1; // invalid private Locale mLocale; @@ -156,6 +160,8 @@ public abstract class BaseStatusBar extends SystemUI implements private Context mLightThemeContext; private ImageUtils mImageUtils = new ImageUtils(); + private UserManager mUserManager; + // UI-specific methods /** @@ -248,12 +254,26 @@ public abstract class BaseStatusBar extends SystemUI implements String action = intent.getAction(); if (Intent.ACTION_USER_SWITCHED.equals(action)) { mCurrentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + updateRelatedUserCache(); if (true) Log.v(TAG, "userId " + mCurrentUserId + " is in the house"); userSwitched(mCurrentUserId); + } else if (Intent.ACTION_USER_ADDED.equals(action)) { + updateRelatedUserCache(); } } }; + private void updateRelatedUserCache() { + synchronized (mRelatedUsers) { + mRelatedUsers.clear(); + if (mUserManager != null) { + for (UserInfo related : mUserManager.getRelatedUsers(mCurrentUserId)) { + mRelatedUsers.put(related.id, related); + } + } + } + } + public void start() { mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); mWindowManagerService = WindowManagerGlobal.getWindowManagerService(); @@ -287,6 +307,8 @@ public abstract class BaseStatusBar extends SystemUI implements mLocale = mContext.getResources().getConfiguration().locale; mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); ArrayList<IBinder> notificationKeys = new ArrayList<IBinder>(); @@ -348,22 +370,28 @@ public abstract class BaseStatusBar extends SystemUI implements IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(Intent.ACTION_USER_ADDED); mContext.registerReceiver(mBroadcastReceiver, filter); + + updateRelatedUserCache(); } public void userSwitched(int newUserId) { // should be overridden } - public boolean notificationIsForCurrentUser(StatusBarNotification n) { + public boolean notificationIsForCurrentOrRelatedUser(StatusBarNotification n) { final int thisUserId = mCurrentUserId; final int notificationUserId = n.getUserId(); if (DEBUG && MULTIUSER_DEBUG) { Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n, thisUserId, notificationUserId)); } - return notificationUserId == UserHandle.USER_ALL - || thisUserId == notificationUserId; + synchronized (mRelatedUsers) { + return notificationUserId == UserHandle.USER_ALL + || thisUserId == notificationUserId + || mRelatedUsers.get(notificationUserId) != null; + } } @Override @@ -389,13 +417,14 @@ public abstract class BaseStatusBar extends SystemUI implements final String _pkg = n.getPackageName(); final String _tag = n.getTag(); final int _id = n.getId(); + final int _userId = n.getUserId(); vetoButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { // Accessibility feedback v.announceForAccessibility( mContext.getString(R.string.accessibility_notification_dismissed)); try { - mBarService.onNotificationClear(_pkg, _tag, _id); + mBarService.onNotificationClear(_pkg, _tag, _id, _userId); } catch (RemoteException ex) { // system process is dead if we're here. @@ -907,7 +936,7 @@ public abstract class BaseStatusBar extends SystemUI implements PendingIntent contentIntent = sbn.getNotification().contentIntent; if (contentIntent != null) { final View.OnClickListener listener = makeClicker(contentIntent, - sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp); + sbn.getPackageName(), sbn.getTag(), sbn.getId(), isHeadsUp, sbn.getUserId()); content.setOnClickListener(listener); } else { content.setOnClickListener(null); @@ -1017,7 +1046,7 @@ public abstract class BaseStatusBar extends SystemUI implements TextView debug = (TextView) row.findViewById(R.id.debug_info); if (debug != null) { debug.setVisibility(View.VISIBLE); - debug.setText("U " + entry.notification.getUserId()); + debug.setText("CU " + mCurrentUserId +" NU " + entry.notification.getUserId()); } } entry.row = row; @@ -1030,9 +1059,9 @@ public abstract class BaseStatusBar extends SystemUI implements return true; } - public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, int id, - boolean forHun) { - return new NotificationClicker(intent, pkg, tag, id, forHun); + public NotificationClicker makeClicker(PendingIntent intent, String pkg, String tag, + int id, boolean forHun, int userId) { + return new NotificationClicker(intent, pkg, tag, id, forHun, userId); } protected class NotificationClicker implements View.OnClickListener { @@ -1041,14 +1070,16 @@ public abstract class BaseStatusBar extends SystemUI implements private String mTag; private int mId; private boolean mIsHeadsUp; + private int mUserId; public NotificationClicker(PendingIntent intent, String pkg, String tag, int id, - boolean forHun) { + boolean forHun, int userId) { mIntent = intent; mPkg = pkg; mTag = tag; mId = id; mIsHeadsUp = forHun; + mUserId = userId; } public void onClick(View v) { @@ -1084,7 +1115,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (mIsHeadsUp) { mHandler.sendEmptyMessage(MSG_HIDE_HEADS_UP); } - mBarService.onNotificationClick(mPkg, mTag, mId); + mBarService.onNotificationClick(mPkg, mTag, mId, mUserId); } catch (RemoteException ex) { // system process is dead if we're here. } @@ -1122,7 +1153,8 @@ public abstract class BaseStatusBar extends SystemUI implements void handleNotificationError(IBinder key, StatusBarNotification n, String message) { removeNotification(key); try { - mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), n.getInitialPid(), message); + mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(), + n.getInitialPid(), message, n.getUserId()); } catch (RemoteException ex) { // The end is nigh. } @@ -1391,7 +1423,7 @@ public abstract class BaseStatusBar extends SystemUI implements updateNotificationVetoButton(oldEntry.row, notification); // Is this for you? - boolean isForCurrentUser = notificationIsForCurrentUser(notification); + boolean isForCurrentUser = notificationIsForCurrentOrRelatedUser(notification); if (DEBUG) Log.d(TAG, "notification is " + (isForCurrentUser ? "" : "not ") + "for you"); // Restart the ticker if it's still running @@ -1443,7 +1475,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (contentIntent != null) { final View.OnClickListener listener = makeClicker(contentIntent, notification.getPackageName(), notification.getTag(), notification.getId(), - isHeadsUp); + isHeadsUp, notification.getUserId()); entry.content.setOnClickListener(listener); } else { entry.content.setOnClickListener(null); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 237b7f7..6be6d4d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import android.provider.Settings; import android.util.AttributeSet; import android.util.EventLog; import android.view.MotionEvent; @@ -57,17 +56,6 @@ public class NotificationPanelView extends PanelView { mHandleBar = resources.getDrawable(R.drawable.status_bar_close); mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height); mHandleView = findViewById(R.id.handle); - PanelHeaderView header = (PanelHeaderView) findViewById(R.id.header); - ZenModeView zenModeView = (ZenModeView) findViewById(R.id.zenmode); - zenModeView.setAdapter(new ZenModeViewAdapter(mContext) { - @Override - public void configure() { - if (mStatusBar != null) { - mStatusBar.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS); - } - } - }); - header.setZenModeView(zenModeView); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java deleted file mode 100644 index a28324d..0000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHeaderView.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.widget.LinearLayout; - -public class PanelHeaderView extends LinearLayout { - private static final String TAG = "PanelHeaderView"; - private static final boolean DEBUG = false; - - private ZenModeView mZenModeView; - - public PanelHeaderView(Context context) { - super(context); - } - - public PanelHeaderView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setZenModeView(ZenModeView zmv) { - mZenModeView = zmv; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - final boolean rt = super.dispatchTouchEvent(ev); - if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev); - if (mZenModeView != null) { - mZenModeView.dispatchExternalTouchEvent(ev); - } - return rt; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - final boolean rt = super.onInterceptTouchEvent(ev); - if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev); - return rt; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean rt = super.onTouchEvent(event); - if (DEBUG) logTouchEvent("onTouchEvent", rt, event); - return true; - } - - private void logTouchEvent(String method, boolean rt, MotionEvent ev) { - Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + ev); - } -} 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 6718de1..9540bd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1056,7 +1056,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { for (int i=0; i<N; i++) { Entry ent = mNotificationData.get(N-i-1); if (!(provisioned || showNotificationEvenIfUnprovisioned(ent.notification))) continue; - if (!notificationIsForCurrentUser(ent.notification)) continue; + + // TODO How do we want to badge notifcations from related users. + if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue; + final int vis = ent.notification.getNotification().visibility; if (vis != Notification.VISIBILITY_SECRET) { // when isLockscreenPublicMode() we show the public form of VISIBILITY_PRIVATE notifications @@ -1114,7 +1117,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { Entry ent = mNotificationData.get(N-i-1); if (!((provisioned && ent.notification.getScore() >= HIDE_ICONS_BELOW_SCORE) || showNotificationEvenIfUnprovisioned(ent.notification))) continue; - if (!notificationIsForCurrentUser(ent.notification)) continue; + if (!notificationIsForCurrentOrRelatedUser(ent.notification)) continue; if (isLockscreenPublicMode() && ent.notification.getNotification().visibility == Notification.VISIBILITY_SECRET @@ -2121,7 +2124,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { if (!isDeviceProvisioned()) return; // not for you - if (!notificationIsForCurrentUser(n)) return; + if (!notificationIsForCurrentOrRelatedUser(n)) return; // Show the ticker if one is requested. Also don't do this // until status bar window is attached to the window manager, @@ -2429,7 +2432,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { } try { mPile.setViewRemoval(true); - mBarService.onClearAllNotifications(); + mBarService.onClearAllNotifications(mCurrentUserId); } catch (Exception ex) { } } }; @@ -2607,7 +2610,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode { mBarService.onNotificationClear( mInterruptingNotificationEntry.notification.getPackageName(), mInterruptingNotificationEntry.notification.getTag(), - mInterruptingNotificationEntry.notification.getId()); + mInterruptingNotificationEntry.notification.getId(), + mInterruptingNotificationEntry.notification.getUserId()); } catch (android.os.RemoteException ex) { // oh well } 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 c1c8946..8170b5a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java @@ -52,13 +52,16 @@ import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Profile; import android.provider.Settings; import android.security.KeyChain; +import android.text.TextUtils.TruncateAt; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; +import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; @@ -586,6 +589,31 @@ class QuickSettings { }); parent.addView(airplaneTile); + // Zen Mode + final QuickSettingsBasicTile zenModeTile = new QuickSettingsBasicTile(mContext); + zenModeTile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showZenModeDialog(); + } + }); + mModel.addZenModeTile(zenModeTile, new QuickSettingsModel.RefreshCallback() { + @Override + public void refreshView(QuickSettingsTileView unused, State state) { + zenModeTile.setImageResource(state.iconId); + // TODO cut new assets + zenModeTile.getImageView().setAlpha(state.enabled ? 1 : .2f); + zenModeTile.getImageView().setScaleX(1.5f); + zenModeTile.getImageView().setScaleY(1.5f); + // for landscape version + zenModeTile.getTextView().setMaxLines(2); + zenModeTile.getTextView().setEllipsize(TruncateAt.END); + // TODO content description + zenModeTile.setText(state.label); + } + }); + parent.addView(zenModeTile); + // Bluetooth if (mModel.deviceSupportsBluetooth() || DEBUG_GONE_TILES) { @@ -864,6 +892,31 @@ class QuickSettings { dialog.show(); } + private void showZenModeDialog() { + final Dialog d = new Dialog(mContext); + d.requestWindowFeature(Window.FEATURE_NO_TITLE); + d.setCancelable(true); + d.setCanceledOnTouchOutside(true); + final ZenModeView v = new ZenModeView(mContext); + v.setAdapter(new ZenModeViewAdapter(mContext) { + @Override + public void configure() { + if (mStatusBarService != null) { + mStatusBarService.startSettingsActivity(Settings.ACTION_ZEN_MODE_SETTINGS); + } + d.dismiss(); + } + @Override + public void close() { + d.dismiss(); + } + }); + d.setContentView(v); + d.create(); + d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); + d.show(); + } + private void applyBluetoothStatus() { mModel.onBluetoothStateChange(mBluetoothState); } 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 174cad8..c3c281c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java @@ -38,6 +38,7 @@ import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; @@ -112,6 +113,9 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, public static class RotationLockState extends State { boolean visible = false; } + public static class ZenModeState extends State { + int zenMode = Settings.Global.ZEN_MODE_OFF; + } /** The callback to update a given tile. */ interface RefreshCallback { @@ -294,6 +298,25 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, } } + /** ContentObserver to watch display color space adjustment */ + private class ZenModeObserver extends ContentObserver { + public ZenModeObserver(Handler handler) { + super(handler); + } + + @Override + public void onChange(boolean selfChange) { + onZenModeChanged(); + } + + public void startObserving() { + final ContentResolver cr = mContext.getContentResolver(); + cr.unregisterContentObserver(this); + cr.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this); + } + } + /** Callback for changes to remote display routes. */ private class RemoteDisplayRouteCallback extends MediaRouter.SimpleCallback { @Override @@ -327,6 +350,7 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, private final DisplayInversionObserver mInversionObserver; private final DisplayContrastObserver mContrastObserver; private final DisplayColorSpaceObserver mColorSpaceObserver; + private final ZenModeObserver mZenModeObserver; private final MediaRouter mMediaRouter; private final RemoteDisplayRouteCallback mRemoteDisplayRouteCallback; @@ -349,6 +373,10 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, private RefreshCallback mAirplaneModeCallback; private State mAirplaneModeState = new State(); + private QuickSettingsTileView mZenModeTile; + private RefreshCallback mZenModeCallback; + private ZenModeState mZenModeState = new ZenModeState(); + private QuickSettingsTileView mWifiTile; private RefreshCallback mWifiCallback; private WifiState mWifiState = new WifiState(); @@ -445,6 +473,8 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mContrastObserver.startObserving(); mColorSpaceObserver = new DisplayColorSpaceObserver(mHandler); mColorSpaceObserver.startObserving(); + mZenModeObserver = new ZenModeObserver(mHandler); + mZenModeObserver.startObserving(); mMediaRouter = (MediaRouter)context.getSystemService(Context.MEDIA_ROUTER_SERVICE); rebindMediaRouterAsCurrentUser(); @@ -567,6 +597,30 @@ class QuickSettingsModel implements BluetoothStateChangeCallback, mAirplaneModeCallback.refreshView(mAirplaneModeTile, mAirplaneModeState); } + // Zen Mode + void addZenModeTile(QuickSettingsTileView view, RefreshCallback cb) { + mZenModeTile = view; + mZenModeCallback = cb; + onZenModeChanged(); + } + private void onZenModeChanged() { + final int mode = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); + mZenModeState.enabled = mode != Settings.Global.ZEN_MODE_OFF; + mZenModeState.zenMode = mode; + if (mode == Settings.Global.ZEN_MODE_FULL) { + mZenModeState.iconId = R.drawable.stat_sys_zen_full; + mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_FULL); + } else if (mode == Settings.Global.ZEN_MODE_LIMITED) { + mZenModeState.iconId = R.drawable.stat_sys_zen_limited; + mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_LIMITED); + } else { + mZenModeState.iconId = R.drawable.stat_sys_zen_limited; + mZenModeState.label = ZenModeView.modeToLabel(ZenModeView.Adapter.MODE_LIMITED); + } + mZenModeCallback.refreshView(mZenModeTile, mZenModeState); + } + // Wifi void addWifiTile(QuickSettingsTileView view, RefreshCallback cb) { mWifiTile = view; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java index fa7f96a..d1c7a41 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java @@ -19,22 +19,16 @@ package com.android.systemui.statusbar.phone; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; -import android.animation.ValueAnimator.AnimatorUpdateListener; import android.content.Context; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; -import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.PathShape; -import android.os.AsyncTask; -import android.os.Vibrator; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextPaint; import android.text.method.LinkMovementMethod; -import android.text.style.RelativeSizeSpan; import android.text.style.URLSpan; import android.util.AttributeSet; import android.util.Log; @@ -62,7 +56,7 @@ public class ZenModeView extends RelativeLayout { private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed", Typeface.NORMAL); private static final int GRAY = 0xff999999; //TextAppearance.StatusBar.Expanded.Network - private static final int BACKGROUND = 0xff1d3741; //0x3333b5e5; + private static final int BACKGROUND = 0xff282828; private static final long DURATION = new ValueAnimator().getDuration(); private static final long BOUNCE_DURATION = DURATION / 3; private static final float BOUNCE_SCALE = 0.8f; @@ -73,23 +67,14 @@ public class ZenModeView extends RelativeLayout { private final Context mContext; private final Paint mPathPaint; - private final TextView mHintText; - private final ModeSpinner mModeSpinner; - private final ImageView mCloseButton; private final ImageView mSettingsButton; - private final Rect mLayoutRect = new Rect(); + private final ModeSpinner mModeSpinner; + private final TextView mActionButton; + private final View mDivider; private final UntilPager mUntilPager; private final AlarmWarning mAlarmWarning; - private final int mPopDuration; - - private float mDownY; - private int mDownBottom; - private boolean mPeekable = true; - private boolean mClosing; - private int mBottom; - private int mWidthSpec; + private Adapter mAdapter; - private boolean mPopped; public ZenModeView(Context context) { this(context, null); @@ -100,34 +85,22 @@ public class ZenModeView extends RelativeLayout { if (DEBUG) log("new %s()", getClass().getSimpleName()); mContext = context; - mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - mPathPaint.setStyle(Paint.Style.STROKE); - mPathPaint.setColor(GRAY); - mPathPaint.setStrokeWidth(5); - final int iconSize = mContext.getResources() .getDimensionPixelSize(com.android.internal.R.dimen.notification_large_icon_width); final int topRowSize = iconSize * 2 / 3; + final int p = topRowSize / 7; - mCloseButton = new ImageView(mContext); - mCloseButton.setAlpha(0f); - mCloseButton.setImageDrawable(sd(closePath(topRowSize), topRowSize, mPathPaint)); - addView(mCloseButton, new LayoutParams(topRowSize, topRowSize)); - mCloseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - bounce(v, null); - close(); - } - }); + mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPathPaint.setStyle(Paint.Style.STROKE); + mPathPaint.setColor(GRAY); + mPathPaint.setStrokeWidth(p / 2); mSettingsButton = new ImageView(mContext); - mSettingsButton.setAlpha(0f); - final int p = topRowSize / 7; mSettingsButton.setPadding(p, p, p, p); mSettingsButton.setImageResource(R.drawable.ic_notify_settings_normal); LayoutParams lp = new LayoutParams(topRowSize, topRowSize); - lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + lp.topMargin = p; + lp.leftMargin = p; addView(mSettingsButton, lp); mSettingsButton.setOnClickListener(new View.OnClickListener() { @Override @@ -140,65 +113,65 @@ public class ZenModeView extends RelativeLayout { }); mModeSpinner = new ModeSpinner(mContext); - mModeSpinner.setAlpha(0); - mModeSpinner.setEnabled(false); mModeSpinner.setId(android.R.id.title); lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize); - lp.addRule(RelativeLayout.CENTER_HORIZONTAL); + lp.topMargin = p; + lp.addRule(CENTER_HORIZONTAL); addView(mModeSpinner, lp); - mUntilPager = new UntilPager(mContext, mPathPaint, iconSize); + mActionButton = new TextView(mContext); + mActionButton.setTextColor(GRAY); + mActionButton.setTypeface(CONDENSED); + mActionButton.setTextSize(TypedValue.COMPLEX_UNIT_PX, mActionButton.getTextSize() * 1.2f); + mActionButton.setAllCaps(true); + mActionButton.setGravity(Gravity.CENTER); + mActionButton.setPadding(p, 0, p * 2, 0); + lp = new LayoutParams(LayoutParams.WRAP_CONTENT, topRowSize); + lp.topMargin = p; + lp.addRule(ALIGN_PARENT_RIGHT); + lp.addRule(ALIGN_BASELINE, mModeSpinner.getId()); + addView(mActionButton, lp); + mActionButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + bounce(v, null); + beginOrEnd(); + } + }); + + mDivider = new View(mContext); + mDivider.setId(android.R.id.empty); + mDivider.setBackgroundColor(GRAY); + lp = new LayoutParams(LayoutParams.MATCH_PARENT, 2); + lp.addRule(BELOW, mModeSpinner.getId()); + lp.topMargin = p; + lp.bottomMargin = p; + addView(mDivider, lp); + + mUntilPager = new UntilPager(mContext, mPathPaint, iconSize * 3 / 4); mUntilPager.setId(android.R.id.tabhost); - mUntilPager.setAlpha(0); lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - lp.addRule(BELOW, mModeSpinner.getId()); + lp.addRule(BELOW, mDivider.getId()); addView(mUntilPager, lp); mAlarmWarning = new AlarmWarning(mContext); - mAlarmWarning.setAlpha(0); lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); lp.addRule(CENTER_HORIZONTAL); lp.addRule(BELOW, mUntilPager.getId()); + lp.bottomMargin = p; addView(mAlarmWarning, lp); - - mHintText = new TextView(mContext); - mHintText.setTypeface(CONDENSED); - mHintText.setText("Swipe down for Limited Interruptions"); - mHintText.setGravity(Gravity.CENTER); - mHintText.setTextColor(GRAY); - addView(mHintText, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - - mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms); - } - - private boolean isApplicable() { - return mAdapter != null && mAdapter.isApplicable(); } - private void close() { - mClosing = true; - final int startBottom = mBottom; - final int max = mPeekable ? getExpandedBottom() : startBottom; - mHintText.animate().alpha(1).setUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - final float f = animation.getAnimatedFraction(); - final int hintBottom = mHintText.getBottom(); - final boolean isDone = f == 1; - setPeeked(hintBottom + (int)((1-f) * (startBottom - hintBottom)), max, isDone); - if (isDone) { - mPeekable = true; - mPopped = false; - mClosing = false; - mModeSpinner.updateState(); - if (mAdapter != null) { - mAdapter.cancel(); - } - } - } - }).start(); - mUntilPager.animate().alpha(0).start(); - mAlarmWarning.animate().alpha(0).start(); + private void beginOrEnd() { + if (mAdapter == null) return; + if (mAdapter.getMode() == mAdapter.getCommittedMode()) { + // end + mAdapter.setCommittedMode(Adapter.MODE_OFF); + } else { + // begin + mAdapter.setCommittedMode(mAdapter.getMode()); + } + mAdapter.close(); } public void setAdapter(Adapter adapter) { @@ -218,180 +191,41 @@ public class ZenModeView extends RelativeLayout { } private void updateState(boolean animate) { - final boolean applicable = isApplicable(); - setVisibility(applicable ? VISIBLE : GONE); - if (!applicable) { - return; - } - if (mAdapter != null && mAdapter.getMode() == Adapter.MODE_OFF && !mPeekable) { - close(); - } else { - mModeSpinner.updateState(); - mUntilPager.updateState(); - mAlarmWarning.updateState(animate); - final float settingsAlpha = getSettingsButtonAlpha(); - if (settingsAlpha != mSettingsButton.getAlpha()) { - if (animate) { - mSettingsButton.animate().alpha(settingsAlpha).start(); - } else { - mSettingsButton.setAlpha(settingsAlpha); - } - } - if (mPeekable && mAdapter != null && mAdapter.getMode() != Adapter.MODE_OFF) { - if (DEBUG) log("panic expand!"); - mPeekable = false; - mModeSpinner.setEnabled(true); - mBottom = getExpandedBottom(); - setExpanded(1); + mModeSpinner.updateState(); + mUntilPager.updateState(); + mAlarmWarning.updateState(animate); + final float settingsAlpha = isFull() ? 0 : SETTINGS_ALPHA; + if (settingsAlpha != mSettingsButton.getAlpha()) { + if (animate) { + mSettingsButton.animate().alpha(settingsAlpha).start(); + } else { + mSettingsButton.setAlpha(settingsAlpha); } } + final boolean committed = mAdapter != null + && mAdapter.getMode() == mAdapter.getCommittedMode(); + mActionButton.setText(committed ? "End" : "Begin"); } - private float getSettingsButtonAlpha() { - final boolean full = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL; - final boolean collapsed = mHintText.getAlpha() == 1; - return full || collapsed ? 0 : SETTINGS_ALPHA; - } - - private static Path closePath(int size) { - final int pad = size / 4; - final Path p = new Path(); - p.moveTo(pad, pad); - p.lineTo(size - pad, size - pad); - p.moveTo(size - pad, pad); - p.lineTo(pad, size - pad); - return p; + private boolean isFull() { + return mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (DEBUG) log("onMeasure %s %s", MeasureSpec.toString(widthMeasureSpec), MeasureSpec.toString(heightMeasureSpec)); - final boolean widthExact = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; - - if (!widthExact || (widthMeasureSpec != mWidthSpec)) { - if (DEBUG) log(" super.onMeasure"); - final int hms = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - super.onMeasure(widthMeasureSpec, hms); - mBottom = mPeekable ? mHintText.getMeasuredHeight() : getExpandedBottom(); - mWidthSpec = widthMeasureSpec; + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (!isFull()) { + final LayoutParams lp = (LayoutParams) mModeSpinner.getLayoutParams(); + final int mh = vh(mModeSpinner) + vh(mDivider) + vh(mUntilPager) + lp.topMargin; + setMeasuredDimension(getMeasuredWidth(), mh); } - if (DEBUG) log("mBottom (OM) = " + mBottom); - setMeasuredDimension(getMeasuredWidth(), mBottom); - if (DEBUG) log(" mw=%s mh=%s", - toString(getMeasuredWidthAndState()), toString(getMeasuredHeightAndState())); - } - - private static String toString(int sizeAndState) { - final int size = sizeAndState & MEASURED_SIZE_MASK; - final boolean tooSmall = (sizeAndState & MEASURED_STATE_TOO_SMALL) != 0; - return size + (tooSmall ? "TOO SMALL" : ""); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - mLayoutRect.set(left, top, right, bottom); - if (DEBUG) log("onLayout %s %s %dx%d", changed, - mLayoutRect.toShortString(), mLayoutRect.width(), mLayoutRect.height()); - super.onLayout(changed, left, top, right, bottom); } - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - final boolean rt = super.dispatchTouchEvent(ev); - if (DEBUG) logTouchEvent("dispatchTouchEvent", rt, ev); - return rt; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent ev) { - final boolean rt = super.onInterceptTouchEvent(ev); - if (DEBUG) logTouchEvent("onInterceptTouchEvent", rt, ev); - if (isApplicable() - && ev.getAction() == MotionEvent.ACTION_DOWN - && ev.getY() > mCloseButton.getBottom() - && mPeekable) { - return true; - } - return rt; - } - - private static void logTouchEvent(String method, boolean rt, MotionEvent event) { - final String action = MotionEvent.actionToString(event.getAction()); - Log.d(TAG, method + " " + (rt ? "TRUE" : "FALSE") + " " + action); - } - - private int getExpandedBottom() { - int b = mModeSpinner.getMeasuredHeight() + mUntilPager.getMeasuredHeight(); - if (mAlarmWarning.getAlpha() == 1) b += mAlarmWarning.getMeasuredHeight(); - return b; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean rt = super.onTouchEvent(event); - if (DEBUG) logTouchEvent("onTouchEvent", rt, event); - if (!isApplicable() || !mPeekable) { - return rt; - } - if (event.getAction() == MotionEvent.ACTION_DOWN) { - mDownY = event.getY(); - if (DEBUG) log(" mDownY=" + mDownY); - mDownBottom = mBottom; - return true; - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - final float dy = event.getY() - mDownY; - if (!mPopped) { - mPopped = true; - AsyncTask.execute(mPopVibration); - } - setPeeked(mDownBottom + (int)dy, getExpandedBottom(), false); - } else if (event.getAction() == MotionEvent.ACTION_UP - || event.getAction() == MotionEvent.ACTION_CANCEL) { - final float dy = event.getY() - mDownY; - setPeeked(mDownBottom + (int)dy, getExpandedBottom(), true); - if (mPeekable) { - close(); - } - } - return rt; - } - - private void setPeeked(int peeked, int max, boolean isDone) { - if (DEBUG) log("setPeeked=" + peeked); - final int min = mHintText.getBottom(); - peeked = Math.max(min, Math.min(peeked, max)); - if (!isDone && mBottom == peeked) { - return; - } - if (peeked == max && isDone) { - mPeekable = false; - mModeSpinner.setEnabled(true); - if (mAdapter != null) { - mAdapter.setMode(Adapter.MODE_LIMITED); - } - } - if (peeked == min) { - mPeekable = true; - mModeSpinner.setEnabled(false); - } - if (DEBUG) log(" mBottom=" + peeked); - mBottom = peeked; - final float f = (peeked - min) / (float)(max - min); - setExpanded(f); - requestLayout(); - } - - private void setExpanded(float f) { - if (DEBUG) log("setExpanded " + f); - final int a = (int)(Color.alpha(BACKGROUND) * f); - setBackgroundColor(Color.argb(a, - Color.red(BACKGROUND), Color.green(BACKGROUND), Color.blue(BACKGROUND))); - mHintText.setAlpha(1 - f); - mCloseButton.setAlpha(f); - mModeSpinner.setAlpha(f); - mUntilPager.setAlpha(f); - mSettingsButton.setAlpha(f * getSettingsButtonAlpha()); + private int vh(View v) { + LayoutParams lp = (LayoutParams) v.getLayoutParams(); + return v.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } private static void log(String msg, Object... args) { @@ -406,12 +240,6 @@ public class ZenModeView extends RelativeLayout { return sd; } - public void dispatchExternalTouchEvent(MotionEvent ev) { - if (isApplicable()) { - onTouchEvent(ev); - } - } - private static void bounce(final View v, final Runnable midBounce) { v.animate().scaleX(BOUNCE_SCALE).scaleY(BOUNCE_SCALE).setDuration(DURATION / 3) .setListener(new AnimatorListenerAdapter() { @@ -429,13 +257,18 @@ public class ZenModeView extends RelativeLayout { }).start(); } - private final Runnable mPopVibration = new Runnable() { - @Override - public void run() { - Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); - v.vibrate(mPopDuration); - } - }; + public static String modeToString(int mode) { + if (mode == Adapter.MODE_OFF) return "MODE_OFF"; + if (mode == Adapter.MODE_LIMITED) return "MODE_LIMITED"; + if (mode == Adapter.MODE_FULL) return "MODE_FULL"; + throw new IllegalArgumentException("Invalid mode: " + mode); + } + + public static String modeToLabel(int mode) { + if (mode == Adapter.MODE_LIMITED) return "Limited interruptions"; + if (mode == Adapter.MODE_FULL) return "Zero interruptions"; + throw new UnsupportedOperationException("Unsupported mode: " + mode); + } private final class UntilPager extends RelativeLayout { private final ImageView mPrev; @@ -448,6 +281,7 @@ public class ZenModeView extends RelativeLayout { public UntilPager(Context context, Paint pathPaint, int iconSize) { super(context); mText1 = new TextView(mContext); + mText1.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText1.getTextSize() * 1.2f); mText1.setTypeface(CONDENSED); mText1.setTextColor(GRAY); mText1.setGravity(Gravity.CENTER); @@ -456,6 +290,7 @@ public class ZenModeView extends RelativeLayout { mText = mText1; mText2 = new TextView(mContext); + mText2.setTextSize(TypedValue.COMPLEX_UNIT_PX, mText1.getTextSize()); mText2.setTypeface(CONDENSED); mText2.setTextColor(GRAY); mText2.setAlpha(0); @@ -478,7 +313,7 @@ public class ZenModeView extends RelativeLayout { }); lp = new LayoutParams(iconSize, iconSize); - lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); + lp.addRule(ALIGN_PARENT_RIGHT); final View v2 = new View(mContext); v2.setBackgroundColor(BACKGROUND); addView(v2, lp); @@ -532,9 +367,7 @@ public class ZenModeView extends RelativeLayout { } private void setText(final TextView textView, final ExitCondition ec) { - SpannableStringBuilder ss = new SpannableStringBuilder(ec.line1 + "\n" + ec.line2); - ss.setSpan(new RelativeSizeSpan(1.5f), (ec.line1 + "\n").length(), ss.length(), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + SpannableStringBuilder ss = new SpannableStringBuilder(ec.summary); if (ec.action != null) { ss.setSpan(new CustomLinkSpan() { @Override @@ -542,7 +375,7 @@ public class ZenModeView extends RelativeLayout { // TODO wire up links Toast.makeText(mContext, ec.action, Toast.LENGTH_SHORT).show(); } - }, (ec.line1 + "\n").length(), ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); + }, 0, ss.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); textView.setMovementMethod(LinkMovementMethod.getInstance()); } else { textView.setMovementMethod(null); @@ -558,7 +391,7 @@ public class ZenModeView extends RelativeLayout { } private Path prevPath(int size) { - final int hp = size / 3; + final int hp = size * 3 / 8; final int vp = size / 4; final Path p = new Path(); p.moveTo(size - hp, vp); @@ -568,7 +401,7 @@ public class ZenModeView extends RelativeLayout { } private Path nextPath(int size) { - final int hp = size / 3; + final int hp = size * 3 / 8; final int vp = size / 4; Path p = new Path(); p.moveTo(hp, vp); @@ -603,12 +436,14 @@ public class ZenModeView extends RelativeLayout { public static final int MODE_LIMITED = 1; public static final int MODE_FULL = 2; - boolean isApplicable(); void configure(); + void close(); int getMode(); void setMode(int mode); + int getCommittedMode(); + void setCommittedMode(int mode); void select(ExitCondition ec); - void cancel(); + void init(); void setCallbacks(Callbacks callbacks); ExitCondition getExitCondition(int d); int getExitConditionCount(); @@ -637,38 +472,38 @@ public class ZenModeView extends RelativeLayout { } @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { + public View getDropDownView(final int position, View convertView, ViewGroup parent) { if (DEBUG) log("getDropDownView %s cv=%s parent=%s", position, convertView, parent); final TextView tv = convertView != null ? (TextView) convertView : new TextView(context); final int mode = getItem(position); - tv.setText(modeToString(mode)); + tv.setText(modeToLabel(mode)); + final boolean inDropdown = parent instanceof ListView; if (convertView == null) { if (DEBUG) log(" setting up view"); tv.setTextColor(GRAY); tv.setTypeface(CONDENSED); tv.setAllCaps(true); - tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.5f); + tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, tv.getTextSize() * 1.2f); final int p = (int) tv.getTextSize() / 2; - if (parent instanceof ListView) { - tv.setPadding(p, p, p, p); + if (inDropdown) { + tv.setPadding(p, p, 0, p); } else { tv.setGravity(Gravity.CENTER_HORIZONTAL); - tv.setPadding(p, 0, p, 0); + tv.setPadding(p, 0, 0, 0); } } tv.setOnTouchListener(new OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { - if (DEBUG) log("onTouch %s %s", tv.getText(), - MotionEvent.actionToString(event.getAction())); - if (mAdapter != null) { + if (DEBUG) log("onTouch %s %s inDropdown=%s", tv.getText(), + MotionEvent.actionToString(event.getAction()), inDropdown); + if (inDropdown && mAdapter != null) { mAdapter.setMode(mode); } return false; } - }); return tv; } @@ -688,16 +523,10 @@ public class ZenModeView extends RelativeLayout { if (getAdapter().getItem(i).equals(mode)) { if (DEBUG) log(" setting selection = " + i); setSelection(i, true); - return; + onDetachedFromWindow(); } } } - - private String modeToString(int mode) { - if (mode == Adapter.MODE_LIMITED) return "Limited interruptions"; - if (mode == Adapter.MODE_FULL) return "Zero interruptions"; - throw new UnsupportedOperationException("Unsupported mode: " + mode); - } } private final class AlarmWarning extends LinearLayout { @@ -724,29 +553,12 @@ public class ZenModeView extends RelativeLayout { } public void updateState(boolean animate) { - final boolean visible = mAdapter != null && mAdapter.getMode() == Adapter.MODE_FULL; - final float alpha = visible ? 1 : 0; + final float alpha = isFull() ? 1 : 0; if (alpha == getAlpha()) { return; } if (animate) { - final boolean in = alpha == 1; - animate().alpha(alpha).setUpdateListener(new AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (mPeekable || mClosing) { - return; - } - float f = animation.getAnimatedFraction(); - if (!in) { - f = 1 - f; - } - ZenModeView.this.mBottom = mUntilPager.getBottom() - + (int)(mAlarmWarning.getMeasuredHeight() * f); - if (DEBUG) log("mBottom (AW) = " + mBottom); - requestLayout(); - } - }).start(); + animate().alpha(alpha).start(); } else { setAlpha(alpha); requestLayout(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java index 39c4faa..d2067a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java @@ -35,23 +35,19 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { private final Handler mHandler = new Handler(); private final SettingsObserver mObserver; private final List<ExitCondition> mExits = Arrays.asList( - newExit("Until you delete this", "Until", "You delete this")); + newExit("Until you turn this off", "Until", "You turn this off")); private Callbacks mCallbacks; private int mExitIndex; - private boolean mDeviceProvisioned; private int mMode; + private int mCommittedMode; public ZenModeViewAdapter(Context context) { mContext = context; mResolver = mContext.getContentResolver(); mObserver = new SettingsObserver(mHandler); mObserver.init(); - } - - @Override - public boolean isApplicable() { - return mDeviceProvisioned; + init(); } @Override @@ -61,6 +57,18 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { @Override public void setMode(int mode) { + if (mode == mMode) return; + mMode = mode; + dispatchChanged(); + } + + @Override + public int getCommittedMode() { + return mCommittedMode; + } + + @Override + public void setCommittedMode(int mode) { final int v = mode == MODE_LIMITED ? Settings.Global.ZEN_MODE_LIMITED : mode == MODE_FULL ? Settings.Global.ZEN_MODE_FULL : Settings.Global.ZEN_MODE_OFF; @@ -74,12 +82,21 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { } @Override - public void cancel() { + public void init() { if (mExitIndex != 0) { mExitIndex = 0; - mHandler.post(mChange); + dispatchChanged(); + } + final int mode = mCommittedMode == MODE_FULL ? MODE_FULL : MODE_LIMITED; + if (mode != mMode) { + mMode = mode; + dispatchChanged(); } - setMode(MODE_OFF); + } + + private void dispatchChanged() { + mHandler.removeCallbacks(mChanged); + mHandler.post(mChanged); } @Override @@ -111,7 +128,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { return; } mExitIndex = i; - mHandler.post(mChange); + dispatchChanged(); } private static ExitCondition newExit(String summary, String line1, String line2) { @@ -122,7 +139,7 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { return rt; } - private final Runnable mChange = new Runnable() { + private final Runnable mChanged = new Runnable() { public void run() { if (mCallbacks == null) { return; @@ -145,24 +162,19 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter { mResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false, this); - mResolver.registerContentObserver( - Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), - false, this); } @Override public void onChange(boolean selfChange) { loadSettings(); - mChange.run(); // already on handler + mChanged.run(); // already on handler } private void loadSettings() { - mDeviceProvisioned = Settings.Global.getInt(mResolver, - Settings.Global.DEVICE_PROVISIONED, 0) != 0; - mMode = getMode(); + mCommittedMode = getModeFromSetting(); } - private int getMode() { + private int getModeFromSetting() { final int v = Settings.Global.getInt(mResolver, Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); if (v == Settings.Global.ZEN_MODE_LIMITED) return MODE_LIMITED; diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java index b9b87b1..e45b98c 100644 --- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java @@ -340,6 +340,13 @@ public class WallpaperCropActivity extends Activity { getWindowManager()); // Get the crop RectF cropRect = mCropView.getCrop(); + + // Due to rounding errors in the cropview renderer the edges can be slightly offset + // therefore we ensure that the boundaries are sanely defined + cropRect.left = Math.max(0, cropRect.left); + cropRect.right = Math.min(mCropView.getWidth(), cropRect.right); + cropRect.top = Math.max(0, cropRect.top); + cropRect.bottom = Math.min(mCropView.getHeight(), cropRect.bottom); int cropRotation = mCropView.getImageRotation(); float cropScale = mCropView.getWidth() / (float) cropRect.width(); diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 15a68ef..1cca164 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -3417,18 +3417,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) { if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); mTopFullscreenOpaqueWindowState = win; - if (showWhenLocked && !mHideWindowBehindKeyguard) { - if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mHideLockScreen to true by win " + win); - mHideLockScreen = true; - mForceStatusBarFromKeyguard = false; - } - if ((fl & FLAG_DISMISS_KEYGUARD) != 0 - && mDismissKeyguard == DISMISS_KEYGUARD_NONE) { - if (DEBUG_LAYOUT) Slog.v(TAG, "Setting mDismissKeyguard true by win " + win); - mDismissKeyguard = mWinDismissingKeyguard == win ? - DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; - mWinDismissingKeyguard = win; - mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure(); + if (!mHideWindowBehindKeyguard) { + if (showWhenLocked) { + if (DEBUG_LAYOUT) Slog.v(TAG, + "Setting mHideLockScreen to true by win " + win); + mHideLockScreen = true; + mForceStatusBarFromKeyguard = false; + } + if ((fl & FLAG_DISMISS_KEYGUARD) != 0 + && mDismissKeyguard == DISMISS_KEYGUARD_NONE) { + if (DEBUG_LAYOUT) Slog.v(TAG, + "Setting mDismissKeyguard true by win " + win); + mDismissKeyguard = mWinDismissingKeyguard == win ? + DISMISS_KEYGUARD_CONTINUE : DISMISS_KEYGUARD_START; + mWinDismissingKeyguard = win; + mForceStatusBarFromKeyguard = mShowingLockscreen && isKeyguardSecure(); + } } if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { mAllowLockscreenWhenOn = true; diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 399e7d1..0f78c9b 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -52,12 +52,12 @@ option java_package com.android.server # NotificationManagerService.java # --------------------------- # when a NotificationManager.notify is called -2750 notification_enqueue (pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3) +2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3) # when someone tries to cancel a notification, the notification manager sometimes # calls this with flags too -2751 notification_cancel (pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1) +2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) # when someone tries to cancel all of the notifications for a particular package -2752 notification_cancel_all (pkg|3),(userid|1|5),(required_flags|1),(forbidden_flags|1) +2752 notification_cancel_all (uid|1|5),(pid|1|5),(pkg|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) # --------------------------- diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 3dcb488..e6163bd 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -457,6 +457,9 @@ public class LocationManagerService extends ILocationManager.Stub { * @param userId the new active user's UserId */ private void switchUser(int userId) { + if (mCurrentUserId == userId) { + return; + } mBlacklist.switchUser(userId); mLocationHandler.removeMessages(MSG_LOCATION_CHANGED); synchronized (mLock) { diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index c9f9a25..1ed943c 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -142,25 +142,40 @@ public class NsdService extends INsdManager.Stub { class DefaultState extends State { @Override public boolean processMessage(Message msg) { + ClientInfo cInfo = null; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { AsyncChannel c = (AsyncChannel) msg.obj; if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + cInfo = new ClientInfo(c, msg.replyTo); mClients.put(msg.replyTo, cInfo); } else { Slog.e(TAG, "Client connection failure, error=" + msg.arg1); } break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - Slog.e(TAG, "Send failed, client connection lost"); - } else { - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + switch (msg.arg1) { + case AsyncChannel.STATUS_SEND_UNSUCCESSFUL: + Slog.e(TAG, "Send failed, client connection lost"); + break; + case AsyncChannel.STATUS_REMOTE_DISCONNECTION: + if (DBG) Slog.d(TAG, "Client disconnected"); + break; + default: + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + break; + } + cInfo = mClients.get(msg.replyTo); + if (cInfo != null) { + cInfo.expungeAllRequests(); + mClients.remove(msg.replyTo); + } + //Last client + if (mClients.size() == 0) { + stopMDnsDaemon(); } - mClients.remove(msg.replyTo); break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -238,13 +253,15 @@ public class NsdService extends INsdManager.Stub { return false; } - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { + private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { clientInfo.mClientIds.put(clientId, globalId); + clientInfo.mClientRequests.put(clientId, what); mIdToClientInfoMap.put(globalId, clientInfo); } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { clientInfo.mClientIds.remove(clientId); + clientInfo.mClientRequests.remove(clientId); mIdToClientInfoMap.remove(globalId); } @@ -264,10 +281,6 @@ public class NsdService extends INsdManager.Stub { result = NOT_HANDLED; break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - //Last client - if (mClients.size() == 1) { - stopMDnsDaemon(); - } result = NOT_HANDLED; break; case NsdManager.DISABLE: @@ -291,7 +304,7 @@ public class NsdService extends INsdManager.Stub { Slog.d(TAG, "Discover " + msg.arg2 + " " + id + servInfo.getServiceType()); } - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo); } else { stopServiceDiscovery(id); @@ -330,7 +343,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (registerService(id, (NsdServiceInfo) msg.obj)) { if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); // Return success after mDns reports success } else { unregisterService(id); @@ -371,7 +384,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (resolveService(id, servInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); } else { replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -477,7 +490,7 @@ public class NsdService extends INsdManager.Stub { int id2 = getUniqueId(); if (getAddrInfo(id2, cooked[3])) { - storeRequestMap(clientId, id2, clientInfo); + storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR, clientId); @@ -821,6 +834,9 @@ public class NsdService extends INsdManager.Stub { /* A map from client id to unique id sent to mDns */ private SparseArray<Integer> mClientIds = new SparseArray<Integer>(); + /* A map from client id to the type of the request we had received */ + private SparseArray<Integer> mClientRequests = new SparseArray<Integer>(); + private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; mMessenger = m; @@ -834,10 +850,41 @@ public class NsdService extends INsdManager.Stub { sb.append("mMessenger ").append(mMessenger).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); for(int i = 0; i< mClientIds.size(); i++) { - sb.append("clientId ").append(mClientIds.keyAt(i)); - sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n"); + int clientID = mClientIds.keyAt(i); + sb.append("clientId ").append(clientID). + append(" mDnsId ").append(mClientIds.valueAt(i)). + append(" type ").append(mClientRequests.get(clientID)).append("\n"); } return sb.toString(); } + + // Remove any pending requests from the global map when we get rid of a client, + // and send cancellations to the daemon. + private void expungeAllRequests() { + int globalId, clientId, i; + for (i = 0; i < mClientIds.size(); i++) { + clientId = mClientIds.keyAt(i); + globalId = mClientIds.valueAt(i); + mIdToClientInfoMap.remove(globalId); + if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId + + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); + switch (mClientRequests.get(clientId)) { + case NsdManager.DISCOVER_SERVICES: + stopServiceDiscovery(globalId); + break; + case NsdManager.RESOLVE_SERVICE: + stopResolveService(globalId); + break; + case NsdManager.REGISTER_SERVICE: + unregisterService(globalId); + break; + default: + break; + } + } + mClientIds.clear(); + mClientRequests.clear(); + } + } } diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index ad693d0..94f699f 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -173,7 +173,9 @@ final class UiModeManagerService extends SystemService { mDeskModeKeepsScreenOn = (context.getResources().getInteger( com.android.internal.R.integer.config_deskDockKeepsScreenOn) == 1); mTelevision = context.getPackageManager().hasSystemFeature( - PackageManager.FEATURE_TELEVISION); + PackageManager.FEATURE_TELEVISION) || + context.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_LEANBACK); mNightMode = Settings.Secure.getInt(context.getContentResolver(), Settings.Secure.UI_NIGHT_MODE, UiModeManager.MODE_NIGHT_AUTO); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 128f636..ab7d60a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -3319,20 +3319,35 @@ public final class ActivityManagerService extends ActivityManagerNative return; } // Remove any existing entries that are the same kind of task. + final Intent intent = task.intent; + final boolean document = intent != null && intent.isDocument(); for (int i=0; i<N; i++) { TaskRecord tr = mRecentTasks.get(i); - if (task.userId == tr.userId - && ((task.affinity != null && task.affinity.equals(tr.affinity)) - || (task.intent != null && task.intent.filterEquals(tr.intent)))) { - tr.disposeThumbnail(); - mRecentTasks.remove(i); - i--; - N--; - if (task.intent == null) { - // If the new recent task we are adding is not fully - // specified, then replace it with the existing recent task. - task = tr; + if (task != tr) { + if (task.userId != tr.userId) { + continue; + } + final Intent trIntent = tr.intent; + if ((task.affinity == null || !task.affinity.equals(tr.affinity)) && + (intent == null || !intent.filterEquals(trIntent))) { + continue; } + if (document || trIntent != null && trIntent.isDocument()) { + // Document tasks do not match other tasks. + continue; + } + } + + // Either task and tr are the same or, their affinities match or their intents match + // and neither of them is a document. + tr.disposeThumbnail(); + mRecentTasks.remove(i); + i--; + N--; + if (task.intent == null) { + // If the new recent task we are adding is not fully + // specified, then replace it with the existing recent task. + task = tr; } } if (N >= MAX_RECENT_TASKS) { @@ -7047,11 +7062,11 @@ public final class ActivityManagerService extends ActivityManagerNative * TODO: Add mController hook */ @Override - public void moveTaskToFront(int task, int flags, Bundle options) { + public void moveTaskToFront(int taskId, int flags, Bundle options) { enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()"); - if (DEBUG_STACK) Slog.d(TAG, "moveTaskToFront: moving task=" + task); + if (DEBUG_STACK) Slog.d(TAG, "moveTaskToFront: moving taskId=" + taskId); synchronized(this) { if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), Binder.getCallingUid(), "Task to front")) { @@ -7060,6 +7075,14 @@ public final class ActivityManagerService extends ActivityManagerNative } final long origId = Binder.clearCallingIdentity(); try { + final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + if (task == null) { + return; + } + if (mStackSupervisor.isLockTaskModeViolation(task)) { + Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode"); + return; + } mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options); } finally { Binder.restoreCallingIdentity(origId); @@ -7269,6 +7292,85 @@ public final class ActivityManagerService extends ActivityManagerNative } } + private boolean isLockTaskAuthorized(ComponentName name) { +// enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, +// "startLockTaskMode()"); +// DevicePolicyManager dpm = (DevicePolicyManager) +// mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); +// return dpm != null && dpm.isLockTaskPermitted(name); + return true; + } + + private void startLockTaskMode(TaskRecord task) { + if (!isLockTaskAuthorized(task.intent.getComponent())) { + return; + } + long ident = Binder.clearCallingIdentity(); + try { + synchronized (this) { + // Since we lost lock on task, make sure it is still there. + task = mStackSupervisor.anyTaskForIdLocked(task.taskId); + if (task != null) { + mStackSupervisor.setLockTaskModeLocked(task); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public void startLockTaskMode(int taskId) { + long ident = Binder.clearCallingIdentity(); + try { + final TaskRecord task; + synchronized (this) { + task = mStackSupervisor.anyTaskForIdLocked(taskId); + } + if (task != null) { + startLockTaskMode(task); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public void startLockTaskMode(IBinder token) { + long ident = Binder.clearCallingIdentity(); + try { + final TaskRecord task; + synchronized (this) { + final ActivityRecord r = ActivityRecord.forToken(token); + if (r == null) { + return; + } + task = r.task; + } + if (task != null) { + startLockTaskMode(task); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public void stopLockTaskMode() { +// enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, +// "stopLockTaskMode()"); + synchronized (this) { + mStackSupervisor.setLockTaskModeLocked(null); + } + } + + @Override + public boolean isInLockTaskMode() { + synchronized (this) { + return mStackSupervisor.isInLockTaskMode(); + } + } + // ========================================================= // THUMBNAILS // ========================================================= @@ -16186,6 +16288,8 @@ public final class ActivityManagerService extends ActivityManagerNative return true; } + mStackSupervisor.setLockTaskModeLocked(null); + final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId); if (userInfo == null) { Slog.w(TAG, "No user info for user #" + userId); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 087ad83c..25292a0 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -36,8 +36,6 @@ import static com.android.server.am.ActivityStackSupervisor.DEBUG_SAVED_STATE; import static com.android.server.am.ActivityStackSupervisor.DEBUG_STATES; import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; -import android.os.Trace; -import android.util.Log; import com.android.internal.os.BatteryStatsImpl; import com.android.server.Watchdog; import com.android.server.am.ActivityManagerService.ItemMatcher; @@ -494,6 +492,9 @@ final class ActivityStack { cls = new ComponentName(info.packageName, info.targetActivity); } final int userId = UserHandle.getUserId(info.applicationInfo.uid); + boolean isDocument = intent != null & intent.isDocument(); + // If documentData is non-null then it must match the existing task data. + Uri documentData = isDocument ? intent.getData() : null; if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this); for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { @@ -510,23 +511,39 @@ final class ActivityStack { continue; } + final Intent taskIntent = task.intent; + final Intent affinityIntent = task.affinityIntent; + final boolean taskIsDocument; + final Uri taskDocumentData; + if (taskIntent != null && taskIntent.isDocument()) { + taskIsDocument = true; + taskDocumentData = taskIntent.getData(); + } else if (affinityIntent != null && affinityIntent.isDocument()) { + taskIsDocument = true; + taskDocumentData = affinityIntent.getData(); + } else { + taskIsDocument = false; + taskDocumentData = null; + } + if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls=" - + r.task.intent.getComponent().flattenToShortString() + + taskIntent.getComponent().flattenToShortString() + "/aff=" + r.task.affinity + " to new cls=" + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity); - if (task.affinity != null) { - if (task.affinity.equals(info.taskAffinity)) { + if (!isDocument && !taskIsDocument && task.affinity != null) { + if (task.affinity.equals(target.taskAffinity)) { if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!"); return r; } - } else if (task.intent != null && task.intent.getComponent().equals(cls)) { + } else if (taskIntent != null && taskIntent.getComponent().equals(cls) && + Objects.equals(documentData, taskDocumentData)) { if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!"); //dump(); if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: " + r.intent); return r; - } else if (task.affinityIntent != null - && task.affinityIntent.getComponent().equals(cls)) { + } else if (affinityIntent != null && affinityIntent.getComponent().equals(cls) && + Objects.equals(documentData, taskDocumentData)) { if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!"); //dump(); if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: " @@ -1859,7 +1876,7 @@ final class ActivityStack { // If the caller has requested that the target task be // reset, then do so. if ((r.intent.getFlags() - &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { + & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { resetTaskIfNeededLocked(r, r); doShow = topRunningNonDelayedActivityLocked(null) == r; } @@ -2008,14 +2025,7 @@ final class ActivityStack { + " out to new task " + target.task); } - if (clearWhenTaskReset) { - // This is the start of a new sub-task. - if (target.thumbHolder == null) { - target.thumbHolder = new ThumbnailHolder(); - } - } else { - target.thumbHolder = newThumbHolder; - } + target.thumbHolder = newThumbHolder; final int targetTaskId = targetTask.taskId; mWindowManager.setAppGroupId(target.appToken, targetTaskId); @@ -2478,14 +2488,15 @@ final class ActivityStack { } r.makeFinishing(); + final TaskRecord task = r.task; EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY, r.userId, System.identityHashCode(r), - r.task.taskId, r.shortComponentName, reason); - final ArrayList<ActivityRecord> activities = r.task.mActivities; + task.taskId, r.shortComponentName, reason); + final ArrayList<ActivityRecord> activities = task.mActivities; final int index = activities.indexOf(r); if (index < (activities.size() - 1)) { - r.task.setFrontOfTask(); - if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { + task.setFrontOfTask(); + if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { // If the caller asked that this activity (and all above it) // be cleared when the task is reset, don't lose that information, // but propagate it up to the next activity. @@ -2524,6 +2535,9 @@ final class ActivityStack { startPausingLocked(false, false); } + if (endTask) { + mStackSupervisor.endLockTaskModeIfTaskEnding(task); + } } else if (r.state != ActivityState.PAUSING) { // If the activity is PAUSING, we will complete the finish once // it is done pausing; else we can just directly finish it here. @@ -3088,23 +3102,6 @@ final class ActivityStack { } } - final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) { - final TaskRecord task = taskForIdLocked(taskId); - if (task != null) { - if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) { - mStackSupervisor.mUserLeaving = true; - } - if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) { - // Caller wants the home activity moved with it. To accomplish this, - // we'll just indicate that this task returns to the home task. - task.mOnTopOfHome = true; - } - moveTaskToFrontLocked(task, null, options); - return true; - } - return false; - } - final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) { if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr); @@ -3162,7 +3159,15 @@ final class ActivityStack { * @return Returns true if the move completed, false if not. */ final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) { - Slog.i(TAG, "moveTaskToBack: " + taskId); + final TaskRecord tr = taskForIdLocked(taskId); + if (tr == null) { + Slog.i(TAG, "moveTaskToBack: bad taskId=" + taskId); + return false; + } + + Slog.i(TAG, "moveTaskToBack: " + tr); + + mStackSupervisor.endLockTaskModeIfTaskEnding(tr); // If we have a watcher, preflight the move before committing to it. First check // for *other* available tasks, but if none are available, then try again allowing the @@ -3190,11 +3195,6 @@ final class ActivityStack { if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId); - final TaskRecord tr = taskForIdLocked(taskId); - if (tr == null) { - return false; - } - mTaskHistory.remove(tr); mTaskHistory.add(0, tr); @@ -3678,6 +3678,7 @@ final class ActivityStack { } void removeTask(TaskRecord task) { + mStackSupervisor.endLockTaskModeIfTaskEnding(task); mWindowManager.removeTask(task.taskId); final ActivityRecord r = mResumedActivity; if (r != null && r.task == task) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 9636de7..3555993 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -17,6 +17,7 @@ package com.android.server.am; import static android.Manifest.permission.START_ANY_ACTIVITY; +import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -231,6 +232,10 @@ public final class ActivityStackSupervisor implements DisplayListener { InputManagerInternal mInputManagerInternal; + /** If non-null then the task specified remains in front and no other tasks may be started + * until the task exits or #stopLockTaskMode() is called. */ + private TaskRecord mLockTaskModeTask; + public ActivityStackSupervisor(ActivityManagerService service) { mService = service; PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); @@ -1198,6 +1203,19 @@ public final class ActivityStackSupervisor implements DisplayListener { resultRecord.removeResultsLocked( sourceRecord, resultWho, requestCode); } + if (sourceRecord.launchedFromUid == callingUid) { + // The new activity is being launched from the same uid as the previous + // activity in the flow, and asking to forward its result back to the + // previous. In this case the activity is serving as a trampoline between + // the two, so we also want to update its launchedFromPackage to be the + // same as the previous activity. Note that this is safe, since we know + // these two packages come from the same uid; the caller could just as + // well have supplied that same package name itself. This specifially + // deals with the case of an intent picker/chooser being launched in the app + // flow to redirect to an activity picked by the user, where we want the final + // activity to consider it to have been launched by the previous app activity. + callingPackage = sourceRecord.launchedFromPackage; + } } if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) { @@ -1426,14 +1444,20 @@ public final class ActivityStackSupervisor implements DisplayListener { } } + final boolean newDocument = intent.isDocument(); if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. - if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { + if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { Slog.w(TAG, "startActivity called from non-Activity context; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent); launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } + } else if (newDocument) { + if (r.launchMode != ActivityInfo.LAUNCH_MULTIPLE) { + Slog.w(TAG, "FLAG_ACTIVITY_NEW_DOCUMENT and launchMode != \"standard\""); + r.launchMode = ActivityInfo.LAUNCH_MULTIPLE; + } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // The original activity who is starting us is running as a single // instance... this new activity it is starting must go on its @@ -1456,7 +1480,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // so we don't want to blindly throw it in to that task. Instead we will take // the NEW_TASK flow and try to find a task for it. But save the task information // so it can be used when creating the new task. - if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { + if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { Slog.w(TAG, "startActivity called from finishing " + sourceRecord + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent); launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; @@ -1472,7 +1496,7 @@ public final class ActivityStackSupervisor implements DisplayListener { sourceStack = null; } - if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // For whatever reason this activity is being launched into a new // task... yet the caller has requested a result back. Well, that // is pretty messed up, so instead immediately send back a cancel @@ -1489,8 +1513,8 @@ public final class ActivityStackSupervisor implements DisplayListener { boolean movedHome = false; TaskRecord reuseTask = null; ActivityStack targetStack; - if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && - (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) + if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && + (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // If bring to front is requested, and no result is requested, and @@ -1505,6 +1529,10 @@ public final class ActivityStackSupervisor implements DisplayListener { ? findTaskLocked(r) : findActivityLocked(intent, r.info); if (intentActivity != null) { + if (isLockTaskModeViolation(intentActivity.task)) { + Slog.e(TAG, "moveTaskToFront: Attempt to violate Lock Task Mode"); + return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; + } if (r.task == null) { r.task = intentActivity.task; } @@ -1675,7 +1703,7 @@ public final class ActivityStackSupervisor implements DisplayListener { if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) { if (top.app != null && top.app.thread != null) { - if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 + if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, @@ -1715,6 +1743,10 @@ public final class ActivityStackSupervisor implements DisplayListener { // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if (isLockTaskModeViolation(reuseTask)) { + Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); + return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; + } targetStack = adjustStackFocus(r); targetStack.moveToFront(); if (reuseTask == null) { @@ -1739,6 +1771,10 @@ public final class ActivityStackSupervisor implements DisplayListener { } } else if (sourceRecord != null) { TaskRecord sourceTask = sourceRecord.task; + if (isLockTaskModeViolation(sourceTask)) { + Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); + return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; + } targetStack = sourceTask.stack; targetStack.moveToFront(); if (!addingToTask && @@ -1782,6 +1818,10 @@ public final class ActivityStackSupervisor implements DisplayListener { // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting // it. + if (isLockTaskModeViolation(sourceTask)) { + Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r); + return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; + } r.setTask(sourceTask, sourceRecord.thumbHolder, false); if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in existing task " + r.task + " from source " + sourceRecord); @@ -2098,17 +2138,18 @@ public final class ActivityStackSupervisor implements DisplayListener { } } - void findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) { - 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) { - if (stacks.get(stackNdx).findTaskToMoveToFrontLocked(taskId, flags, options)) { - if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" - + stacks.get(stackNdx)); - return; - } - } + void findTaskToMoveToFrontLocked(TaskRecord task, int flags, Bundle options) { + if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) { + mUserLeaving = true; } + if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) { + // Caller wants the home activity moved with it. To accomplish this, + // we'll just indicate that this task returns to the home task. + task.mOnTopOfHome = true; + } + task.stack.moveTaskToFrontLocked(task, null, options); + if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack=" + + task.stack); } ActivityStack getStack(int stackId) { @@ -2288,6 +2329,7 @@ public final class ActivityStackSupervisor implements DisplayListener { } } checkReadyForSleepLocked(); + setLockTaskModeLocked(null); } boolean shutdownLocked(int timeout) { @@ -2469,7 +2511,10 @@ public final class ActivityStackSupervisor implements DisplayListener { for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = stacks.get(stackNdx); stack.switchUserLocked(userId); - mWindowManager.moveTaskToTop(stack.topTask().taskId); + TaskRecord task = stack.topTask(); + if (task != null) { + mWindowManager.moveTaskToTop(task.taskId); + } } } @@ -2480,7 +2525,10 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean homeInFront = stack.isHomeStack(); if (stack.isOnHomeDisplay()) { moveHomeStack(homeInFront); - mWindowManager.moveTaskToTop(stack.topTask().taskId); + TaskRecord task = stack.topTask(); + if (task != null) { + mWindowManager.moveTaskToTop(task.taskId); + } } else { // Stack was moved to another display while user was swapped out. resumeHomeActivity(null); @@ -2866,6 +2914,35 @@ public final class ActivityStackSupervisor implements DisplayListener { return list; } + void setLockTaskModeLocked(TaskRecord task) { + if (task == null) { + // Take out of lock task mode. + mLockTaskModeTask = null; + return; + } + if (isLockTaskModeViolation(task)) { + Slog.e(TAG, "setLockTaskMode: Attempt to start a second Lock Task Mode task."); + return; + } + mLockTaskModeTask = task; + findTaskToMoveToFrontLocked(task, 0, null); + resumeTopActivitiesLocked(); + } + + boolean isLockTaskModeViolation(TaskRecord task) { + return mLockTaskModeTask != null && mLockTaskModeTask != task; + } + + void endLockTaskModeIfTaskEnding(TaskRecord task) { + if (mLockTaskModeTask != null && mLockTaskModeTask == task) { + mLockTaskModeTask = null; + } + } + + boolean isInLockTaskMode() { + return mLockTaskModeTask != null; + } + private final class ActivityStackSupervisorHandler extends Handler { public ActivityStackSupervisorHandler(Looper looper) { diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 89acec9..1ff925c 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -21,14 +21,22 @@ import android.media.session.IMediaController; import android.media.session.IMediaControllerCallback; import android.media.session.IMediaSession; import android.media.session.IMediaSessionCallback; -import android.media.RemoteControlClient; +import android.media.session.MediaMetadata; +import android.media.session.PlaybackState; +import android.media.Rating; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; +import android.os.ResultReceiver; import android.util.Log; +import android.util.Slog; import android.view.KeyEvent; import java.util.ArrayList; +import java.util.List; /** * This is the system implementation of a Session. Apps will interact with the @@ -37,6 +45,8 @@ import java.util.ArrayList; public class MediaSessionRecord implements IBinder.DeathRecipient { private static final String TAG = "MediaSessionImpl"; + private final MessageHandler mHandler; + private final int mPid; private final String mPackageName; private final String mTag; @@ -45,13 +55,25 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private final SessionCb mSessionCb; private final MediaSessionService mService; - private final ArrayList<IMediaControllerCallback> mSessionCallbacks = + private final Object mControllerLock = new Object(); + private final ArrayList<IMediaControllerCallback> mControllerCallbacks = new ArrayList<IMediaControllerCallback>(); + private final ArrayList<String> mInterfaces = new ArrayList<String>(); + + private boolean mTransportPerformerEnabled = false; + private Bundle mRoute; + + // TransportPerformer fields - private int mPlaybackState = RemoteControlClient.PLAYSTATE_NONE; + private MediaMetadata mMetadata; + private PlaybackState mPlaybackState; + private int mRatingType; + // End TransportPerformer fields + + private boolean mIsPublished = false; public MediaSessionRecord(int pid, String packageName, IMediaSessionCallback cb, String tag, - MediaSessionService service) { + MediaSessionService service, Handler handler) { mPid = pid; mPackageName = packageName; mTag = tag; @@ -59,6 +81,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mSession = new SessionStub(); mSessionCb = new SessionCb(cb); mService = service; + mHandler = new MessageHandler(handler.getLooper()); } public IMediaSession getSessionBinder() { @@ -69,61 +92,132 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { 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); } + public boolean isPublished() { + return mIsPublished; + } + private void onDestroy() { mService.destroySession(this); } - private final class SessionStub extends IMediaSession.Stub { + private void pushPlaybackStateUpdate() { + synchronized (mControllerLock) { + for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) { + IMediaControllerCallback cb = mControllerCallbacks.get(i); + try { + cb.onPlaybackStateChanged(mPlaybackState); + } catch (RemoteException e) { + Log.w(TAG, "Removing dead callback in pushPlaybackStateUpdate.", e); + mControllerCallbacks.remove(i); + } + } + } + } - @Override - public void setPlaybackState(int state) throws RemoteException { - setPlaybackStateInternal(state); + private void pushMetadataUpdate() { + synchronized (mControllerLock) { + for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) { + IMediaControllerCallback cb = mControllerCallbacks.get(i); + try { + cb.onMetadataChanged(mMetadata); + } catch (RemoteException e) { + Log.w(TAG, "Removing dead callback in pushMetadataUpdate.", e); + mControllerCallbacks.remove(i); + } + } } + } + + private void pushRouteUpdate() { + synchronized (mControllerLock) { + for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) { + IMediaControllerCallback cb = mControllerCallbacks.get(i); + try { + cb.onRouteChanged(mRoute); + } catch (RemoteException e) { + Log.w(TAG, "Removing dead callback in pushRouteUpdate.", e); + mControllerCallbacks.remove(i); + } + } + } + } + + private void pushEvent(String event, Bundle data) { + synchronized (mControllerLock) { + for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) { + IMediaControllerCallback cb = mControllerCallbacks.get(i); + try { + cb.onEvent(event, data); + } catch (RemoteException e) { + Log.w(TAG, "Removing dead callback in pushRouteUpdate.", e); + mControllerCallbacks.remove(i); + } + } + } + } + + private final class SessionStub extends IMediaSession.Stub { @Override - public void destroy() throws RemoteException { + public void destroy() { onDestroy(); } @Override - public void sendEvent(Bundle data) throws RemoteException { + public void sendEvent(String event, Bundle data) { + mHandler.post(MessageHandler.MSG_SEND_EVENT, event, data); } @Override - public IMediaController getMediaSessionToken() throws RemoteException { + public IMediaController getMediaController() { return mController; } @Override - public void setMetadata(Bundle metadata) throws RemoteException { + public void setRouteState(Bundle routeState) { + } + + @Override + public void setRoute(Bundle mediaRouteDescriptor) { + mRoute = mediaRouteDescriptor; + mHandler.post(MessageHandler.MSG_UPDATE_ROUTE); + } + + @Override + public void publish() { + mIsPublished = true; // TODO push update to service + } + @Override + public void setTransportPerformerEnabled() { + mTransportPerformerEnabled = true; } @Override - public void setRouteState(Bundle routeState) throws RemoteException { + public List<String> getSupportedInterfaces() { + return mInterfaces; } @Override - public void setRoute(Bundle medaiRouteDescriptor) throws RemoteException { + public void setMetadata(MediaMetadata metadata) { + mMetadata = metadata; + mHandler.post(MessageHandler.MSG_UPDATE_METADATA); } + @Override + public void setPlaybackState(PlaybackState state) { + mPlaybackState = state; + mHandler.post(MessageHandler.MSG_UPDATE_PLAYBACK_STATE); + } + + @Override + public void setRatingType(int type) { + mRatingType = type; + } } class SessionCb { @@ -139,32 +233,96 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { try { mCb.onMediaButton(mediaButtonIntent); } catch (RemoteException e) { - Log.d(TAG, "Controller object dead in sendMediaRequest.", e); - onDestroy(); + Slog.e(TAG, "Remote failure in sendMediaRequest.", e); + } + } + + public void sendCommand(String command, Bundle extras, ResultReceiver cb) { + try { + mCb.onCommand(command, extras, cb); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in sendCommand.", e); + } + } + + public void play() { + try { + mCb.onPlay(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in play.", e); } } - public void sendCommand(String command, Bundle extras) { + public void pause() { try { - mCb.onCommand(command, extras); + mCb.onPause(); } catch (RemoteException e) { - Log.d(TAG, "Controller object dead in sendCommand.", e); - onDestroy(); + Slog.e(TAG, "Remote failure in pause.", e); } } - public void registerCallbackListener(IMediaSessionCallback cb) { + public void stop() { + try { + mCb.onStop(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in stop.", e); + } + } + public void next() { + try { + mCb.onNext(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in next.", e); + } } + public void previous() { + try { + mCb.onPrevious(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in previous.", e); + } + } + + public void fastForward() { + try { + mCb.onFastForward(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in fastForward.", e); + } + } + + public void rewind() { + try { + mCb.onRewind(); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in rewind.", e); + } + } + + public void seekTo(long pos) { + try { + mCb.onSeekTo(pos); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in seekTo.", e); + } + } + + public void rate(Rating rating) { + try { + mCb.onRate(rating); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in rate.", e); + } + } } class ControllerStub extends IMediaController.Stub { - /* - */ @Override - public void sendCommand(String command, Bundle extras) throws RemoteException { - mSessionCb.sendCommand(command, extras); + public void sendCommand(String command, Bundle extras, ResultReceiver cb) + throws RemoteException { + mSessionCb.sendCommand(command, extras, cb); } @Override @@ -172,29 +330,130 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mSessionCb.sendMediaButton(mediaButtonIntent); } - /* - */ @Override - public void registerCallbackListener(IMediaControllerCallback cb) throws RemoteException { - if (!mSessionCallbacks.contains(cb)) { - mSessionCallbacks.add(cb); + public void registerCallbackListener(IMediaControllerCallback cb) { + synchronized (mControllerLock) { + if (!mControllerCallbacks.contains(cb)) { + mControllerCallbacks.add(cb); + } } } - /* - */ @Override public void unregisterCallbackListener(IMediaControllerCallback cb) throws RemoteException { - mSessionCallbacks.remove(cb); + synchronized (mControllerLock) { + mControllerCallbacks.remove(cb); + } } - /* - */ @Override - public int getPlaybackState() throws RemoteException { + public void play() throws RemoteException { + mSessionCb.play(); + } + + @Override + public void pause() throws RemoteException { + mSessionCb.pause(); + } + + @Override + public void stop() throws RemoteException { + mSessionCb.stop(); + } + + @Override + public void next() throws RemoteException { + mSessionCb.next(); + } + + @Override + public void previous() throws RemoteException { + mSessionCb.previous(); + } + + @Override + public void fastForward() throws RemoteException { + mSessionCb.fastForward(); + } + + @Override + public void rewind() throws RemoteException { + mSessionCb.rewind(); + } + + @Override + public void seekTo(long pos) throws RemoteException { + mSessionCb.seekTo(pos); + } + + @Override + public void rate(Rating rating) throws RemoteException { + mSessionCb.rate(rating); + } + + + @Override + public MediaMetadata getMetadata() { + return mMetadata; + } + + @Override + public PlaybackState getPlaybackState() { return mPlaybackState; } + + @Override + public int getRatingType() { + return mRatingType; + } + + @Override + public boolean isTransportControlEnabled() throws RemoteException { + return mTransportPerformerEnabled; + } + } + + private class MessageHandler extends Handler { + private static final int MSG_UPDATE_METADATA = 1; + private static final int MSG_UPDATE_PLAYBACK_STATE = 2; + private static final int MSG_UPDATE_ROUTE = 3; + private static final int MSG_SEND_EVENT = 4; + + public MessageHandler(Looper looper) { + super(looper); + } + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_METADATA: + pushMetadataUpdate(); + break; + case MSG_UPDATE_PLAYBACK_STATE: + pushPlaybackStateUpdate(); + break; + case MSG_UPDATE_ROUTE: + pushRouteUpdate(); + break; + case MSG_SEND_EVENT: + pushEvent((String) msg.obj, msg.getData()); + break; + } + } + + public void post(int what) { + post(what, null); + } + + public void post(int what, Object obj) { + obtainMessage(what, obj).sendToTarget(); + } + + public void post(int what, Object obj, Bundle data) { + Message msg = obtainMessage(what, obj); + msg.setData(data); + msg.sendToTarget(); + } } } diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index a7ff926..8fe6055 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -21,6 +21,7 @@ import android.media.session.IMediaSession; import android.media.session.IMediaSessionCallback; import android.media.session.IMediaSessionManager; import android.os.Binder; +import android.os.Handler; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; @@ -41,6 +42,8 @@ public class MediaSessionService extends SystemService { private final ArrayList<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>(); private final Object mLock = new Object(); + // TODO do we want a separate thread for handling mediasession messages? + private final Handler mHandler = new Handler(); public MediaSessionService(Context context) { super(context); @@ -91,7 +94,8 @@ public class MediaSessionService extends SystemService { private MediaSessionRecord createSessionLocked(int pid, String packageName, IMediaSessionCallback cb, String tag) { - final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this); + final MediaSessionRecord session = new MediaSessionRecord(pid, packageName, cb, tag, this, + mHandler); try { cb.asBinder().linkToDeath(session, 0); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 243bd74..4c8dcc3 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -20,11 +20,14 @@ import android.os.IBinder; public interface NotificationDelegate { void onSetDisabled(int status); - void onClearAll(); - void onNotificationClick(String pkg, String tag, int id); - void onNotificationClear(String pkg, String tag, int id); - void onNotificationError(String pkg, String tag, int id, - int uid, int initialPid, String message); + void onClearAll(int callingUid, int callingPid, int userId); + void onNotificationClick(int callingUid, int callingPid, + String pkg, String tag, int id, int userId); + void onNotificationClear(int callingUid, int callingPid, + String pkg, String tag, int id, int userId); + void onNotificationError(int callingUid, int callingPid, + String pkg, String tag, int id, + int uid, int initialPid, String message, int userId); void onPanelRevealed(); boolean allowDisable(int what, IBinder token, String pkg); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ce13a7a..e2226aa 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -43,6 +43,7 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -56,6 +57,7 @@ import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; import android.service.notification.INotificationListener; @@ -67,6 +69,7 @@ import android.util.AtomicFile; import android.util.EventLog; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import android.util.Xml; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -217,6 +220,23 @@ public class NotificationManagerService extends SystemService { )); private static final String EXTRA_INTERCEPT = "android.intercept"; + // Users related to the current user. + final protected SparseArray<UserInfo> mRelatedUsers = new SparseArray<UserInfo>(); + + private static final int MY_UID = Process.myUid(); + private static final int MY_PID = Process.myPid(); + private static final int REASON_DELEGATE_CLICK = 1; + private static final int REASON_DELEGATE_CANCEL = 2; + private static final int REASON_DELEGATE_CANCEL_ALL = 3; + private static final int REASON_DELEGATE_ERROR = 4; + private static final int REASON_PACKAGE_CHANGED = 5; + private static final int REASON_USER_STOPPED = 6; + private static final int REASON_PACKAGE_BANNED = 7; + private static final int REASON_NOMAN_CANCEL = 8; + private static final int REASON_NOMAN_CANCEL_ALL = 9; + private static final int REASON_LISTENER_CANCEL = 10; + private static final int REASON_LISTENER_CANCEL_ALL = 11; + private class NotificationListenerInfo implements IBinder.DeathRecipient { INotificationListener listener; ComponentName component; @@ -910,28 +930,23 @@ public class NotificationManagerService extends SystemService { } @Override - public void onClearAll() { - // XXX to be totally correct, the caller should tell us which user - // this is for. - cancelAll(ActivityManager.getCurrentUser()); + public void onClearAll(int callingUid, int callingPid, int userId) { + cancelAll(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null); } @Override - public void onNotificationClick(String pkg, String tag, int id) { - // XXX to be totally correct, the caller should tell us which user - // this is for. - cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL, - Notification.FLAG_FOREGROUND_SERVICE, false, - ActivityManager.getCurrentUser()); + public void onNotificationClick(int callingUid, int callingPid, + String pkg, String tag, int id, int userId) { + cancelNotification(callingUid, callingPid, pkg, tag, id, Notification.FLAG_AUTO_CANCEL, + Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_DELEGATE_CLICK, null); } @Override - public void onNotificationClear(String pkg, String tag, int id) { - // XXX to be totally correct, the caller should tell us which user - // this is for. - cancelNotification(pkg, tag, id, 0, - Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, - true, ActivityManager.getCurrentUser()); + public void onNotificationClear(int callingUid, int callingPid, + String pkg, String tag, int id, int userId) { + cancelNotification(callingUid, callingPid, pkg, tag, id, 0, + Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, + true, userId, REASON_DELEGATE_CANCEL, null); } @Override @@ -968,13 +983,12 @@ public class NotificationManagerService extends SystemService { } @Override - public void onNotificationError(String pkg, String tag, int id, - int uid, int initialPid, String message) { + public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id, + int uid, int initialPid, String message, int userId) { Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")"); - // XXX to be totally correct, the caller should tell us which user - // this is for. - cancelNotification(pkg, tag, id, 0, 0, false, UserHandle.getUserId(uid)); + cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId, + REASON_DELEGATE_ERROR, null); long ident = Binder.clearCallingIdentity(); try { ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg, @@ -1051,8 +1065,8 @@ public class NotificationManagerService extends SystemService { if (pkgList != null && (pkgList.length > 0)) { for (String pkgName : pkgList) { if (cancelNotifications) { - cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart, - UserHandle.USER_ALL); + cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, + UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null); } if (mEnabledListenerPackageNames.contains(pkgName)) { anyListenersInvolved = true; @@ -1082,7 +1096,8 @@ public class NotificationManagerService extends SystemService { } else if (action.equals(Intent.ACTION_USER_STOPPED)) { int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); if (userHandle >= 0) { - cancelAllNotificationsInt(null, 0, 0, true, userHandle); + cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle, + REASON_USER_STOPPED, null); } } else if (action.equals(Intent.ACTION_USER_PRESENT)) { // turn off LED when user passes through lock screen @@ -1090,6 +1105,9 @@ public class NotificationManagerService extends SystemService { } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { // reload per-user settings mSettingsObserver.update(null); + updateRelatedUserCache(context); + } else if (action.equals(Intent.ACTION_USER_ADDED)) { + updateRelatedUserCache(context); } } }; @@ -1223,6 +1241,7 @@ public class NotificationManagerService extends SystemService { filter.addAction(Intent.ACTION_USER_PRESENT); filter.addAction(Intent.ACTION_USER_STOPPED); filter.addAction(Intent.ACTION_USER_SWITCHED); + filter.addAction(Intent.ACTION_USER_ADDED); getContext().registerReceiver(mIntentReceiver, filter); IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED); @@ -1304,7 +1323,8 @@ public class NotificationManagerService extends SystemService { // Now, cancel any outstanding notifications that are part of a just-disabled app if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) { - cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid)); + cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid), + REASON_PACKAGE_BANNED, null); } } @@ -1420,9 +1440,10 @@ public class NotificationManagerService extends SystemService { userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg); // Don't allow client applications to cancel foreground service notis. - cancelNotification(pkg, tag, id, 0, + cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0, Binder.getCallingUid() == Process.SYSTEM_UID - ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId); + ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL, + null); } @Override @@ -1434,7 +1455,9 @@ public class NotificationManagerService extends SystemService { // Calling from user space, don't allow the canceling of actively // running foreground services. - cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId); + cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(), + pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId, + REASON_NOMAN_CANCEL_ALL, null); } @Override @@ -1543,9 +1566,12 @@ public class NotificationManagerService extends SystemService { @Override public void cancelAllNotificationsFromListener(INotificationListener token) { NotificationListenerInfo info = checkListenerToken(token); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - cancelAll(info.userid); + cancelAll(callingUid, callingPid, info.userid, + REASON_LISTENER_CANCEL_ALL, info); } finally { Binder.restoreCallingIdentity(identity); } @@ -1562,12 +1588,14 @@ public class NotificationManagerService extends SystemService { public void cancelNotificationFromListener(INotificationListener token, String pkg, String tag, int id) { NotificationListenerInfo info = checkListenerToken(token); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - cancelNotification(pkg, tag, id, 0, + cancelNotification(callingUid, callingPid, pkg, tag, id, 0, Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE, true, - info.userid); + info.userid, REASON_LISTENER_CANCEL, info); } finally { Binder.restoreCallingIdentity(identity); } @@ -1735,8 +1763,8 @@ public class NotificationManagerService extends SystemService { // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { - EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag, userId, - notification.toString()); + EventLogTags.writeNotificationEnqueue(callingUid, callingPid, + pkg, id, tag, userId, notification.toString()); } if (pkg == null || notification == null) { @@ -2287,9 +2315,10 @@ public class NotificationManagerService extends SystemService { * Cancels a notification ONLY if it has all of the {@code mustHaveFlags} * and none of the {@code mustNotHaveFlags}. */ - void cancelNotification(final String pkg, final String tag, final int id, + void cancelNotification(final int callingUid, final int callingPid, + final String pkg, final String tag, final int id, final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete, - final int userId) { + final int userId, final int reason, final NotificationListenerInfo listener) { // In enqueueNotificationInternal notifications are added by scheduling the // work on the worker handler. Hence, we also schedule the cancel on this // handler to avoid a scenario where an add notification call followed by a @@ -2297,8 +2326,9 @@ public class NotificationManagerService extends SystemService { mHandler.post(new Runnable() { @Override public void run() { - EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, tag, userId, - mustHaveFlags, mustNotHaveFlags); + EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId, + mustHaveFlags, mustNotHaveFlags, reason, + listener == null ? null : listener.component.toShortString()); synchronized (mNotificationList) { int index = indexOfNotificationLocked(pkg, tag, id, userId); @@ -2337,13 +2367,27 @@ public class NotificationManagerService extends SystemService { } /** + * Determine whether the userId applies to the notification in question, either because + * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or + * because it matches a related user. + */ + private boolean notificationMatchesUserIdOrRelated(NotificationRecord r, int userId) { + synchronized (mRelatedUsers) { + return notificationMatchesUserId(r, userId) + || mRelatedUsers.get(r.getUserId()) != null; + } + } + + /** * Cancels all notifications from a given package that have all of the * {@code mustHaveFlags}. */ - boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags, - int mustNotHaveFlags, boolean doit, int userId) { - EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, userId, - mustHaveFlags, mustNotHaveFlags); + boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags, + int mustNotHaveFlags, boolean doit, int userId, int reason, + NotificationListenerInfo listener) { + EventLogTags.writeNotificationCancelAll(callingUid, callingPid, + pkg, userId, mustHaveFlags, mustNotHaveFlags, reason, + listener == null ? null : listener.component.toShortString()); synchronized (mNotificationList) { final int N = mNotificationList.size(); @@ -2418,13 +2462,17 @@ public class NotificationManagerService extends SystemService { } } - void cancelAll(int userId) { + void cancelAll(int callingUid, int callingPid, int userId, int reason, + NotificationListenerInfo listener) { + EventLogTags.writeNotificationCancelAll(callingUid, callingPid, + null, userId, 0, 0, reason, + listener == null ? null : listener.component.toShortString()); synchronized (mNotificationList) { final int N = mNotificationList.size(); for (int i=N-1; i>=0; i--) { NotificationRecord r = mNotificationList.get(i); - if (!notificationMatchesUserId(r, userId)) { + if (!notificationMatchesUserIdOrRelated(r, userId)) { continue; } @@ -2582,6 +2630,20 @@ public class NotificationManagerService extends SystemService { } } + private void updateRelatedUserCache(Context context) { + UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); + int currentUserId = ActivityManager.getCurrentUser(); + if (userManager != null) { + List<UserInfo> relatedUsers = userManager.getRelatedUsers(currentUserId); + synchronized (mRelatedUsers) { + mRelatedUsers.clear(); + for (UserInfo related : relatedUsers) { + mRelatedUsers.put(related.id, related); + } + } + } + } + private boolean isCall(String pkg, Notification n) { return CALL_PACKAGES.contains(pkg); } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index df06bae..81af636 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -165,11 +165,11 @@ final class Notifier { int newFlags, String newTag, String newPackageName, int newOwnerUid, int newOwnerPid, WorkSource newWorkSource, String newHistoryTag) { - final int monitorType = getBatteryStatsWakeLockMonitorType(flags); - final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); - boolean unimportantForLogging = (flags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 - && ownerUid == Process.SYSTEM_UID; if (workSource != null && newWorkSource != null) { + final int monitorType = getBatteryStatsWakeLockMonitorType(flags); + final int newMonitorType = getBatteryStatsWakeLockMonitorType(newFlags); + boolean unimportantForLogging = (newFlags&PowerManager.UNIMPORTANT_FOR_LOGGING) != 0 + && newOwnerUid == Process.SYSTEM_UID; if (DEBUG) { Slog.d(TAG, "onWakeLockChanging: flags=" + newFlags + ", tag=\"" + newTag + "\", packageName=" + newPackageName diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index e0a46b9..fab972f 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -1816,7 +1816,12 @@ public final class PowerManagerService extends com.android.server.SystemService private boolean isScreenOnInternal() { synchronized (mLock) { - return isScreenOnLocked(); + // XXX This is a temporary hack to let certain parts of the system pretend the + // screen is still on even when dozing and we would normally want to report + // screen off. Will be removed when the window manager is modified to use + // the true blanking state of the display. + return isScreenOnLocked() + || mWakefulness == WAKEFULNESS_DOZING; } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 8219eb5..4ce02c1 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -535,11 +535,13 @@ public class StatusBarManagerService extends IStatusBarService.Stub } @Override - public void onNotificationClick(String pkg, String tag, int id) { + public void onNotificationClick(String pkg, String tag, int id, int userId) { enforceStatusBarService(); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onNotificationClick(pkg, tag, id); + mNotificationDelegate.onNotificationClick(callingUid, callingPid, pkg, tag, id, userId); } finally { Binder.restoreCallingIdentity(identity); } @@ -547,34 +549,41 @@ public class StatusBarManagerService extends IStatusBarService.Stub @Override public void onNotificationError(String pkg, String tag, int id, - int uid, int initialPid, String message) { + int uid, int initialPid, String message, int userId) { enforceStatusBarService(); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { // WARNING: this will call back into us to do the remove. Don't hold any locks. - mNotificationDelegate.onNotificationError(pkg, tag, id, uid, initialPid, message); + mNotificationDelegate.onNotificationError(callingUid, callingPid, + pkg, tag, id, uid, initialPid, message, userId); } finally { Binder.restoreCallingIdentity(identity); } } @Override - public void onNotificationClear(String pkg, String tag, int id) { + public void onNotificationClear(String pkg, String tag, int id, int userId) { enforceStatusBarService(); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onNotificationClear(pkg, tag, id); + mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId); } finally { Binder.restoreCallingIdentity(identity); } } @Override - public void onClearAllNotifications() { + public void onClearAllNotifications(int userId) { enforceStatusBarService(); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); long identity = Binder.clearCallingIdentity(); try { - mNotificationDelegate.onClearAll(); + mNotificationDelegate.onClearAll(callingUid, callingPid, userId); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index b925856..efbfb33 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -90,6 +90,7 @@ public class UsbDeviceManager { private static final int MSG_SYSTEM_READY = 3; private static final int MSG_BOOT_COMPLETED = 4; private static final int MSG_USER_SWITCHED = 5; + private static final int MSG_START_ACCESSORY_MODE = 6; private static final int AUDIO_MODE_NONE = 0; private static final int AUDIO_MODE_SOURCE = 1; @@ -152,7 +153,7 @@ public class UsbDeviceManager { mHandler.updateState(state); } else if ("START".equals(accessory)) { if (DEBUG) Slog.d(TAG, "got accessory start"); - startAccessoryMode(); + mHandler.sendEmptyMessage(MSG_START_ACCESSORY_MODE); } } }; @@ -170,7 +171,7 @@ public class UsbDeviceManager { if (nativeIsStartRequested()) { if (DEBUG) Slog.d(TAG, "accessory attached at boot"); - startAccessoryMode(); + mHandler.sendEmptyMessage(MSG_START_ACCESSORY_MODE); } boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false); @@ -232,6 +233,8 @@ public class UsbDeviceManager { functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE; } + if (DEBUG) Slog.d(TAG, "startAccessoryMode: " + functions); + if (functions != null) { mAccessoryModeRequestTime = SystemClock.elapsedRealtime(); setCurrentFunctions(functions, false); @@ -306,6 +309,7 @@ public class UsbDeviceManager { // current USB state private boolean mConnected; private boolean mConfigured; + private boolean mAccessoryStartPending; private String mCurrentFunctions; private String mDefaultFunctions; private UsbAccessory mCurrentAccessory; @@ -612,6 +616,11 @@ public class UsbDeviceManager { case MSG_UPDATE_STATE: mConnected = (msg.arg1 == 1); mConfigured = (msg.arg2 == 1); + + if (!mConnected) { + mAccessoryStartPending = false; + } + updateUsbNotification(); updateAdbNotification(); if (containsFunction(mCurrentFunctions, @@ -625,6 +634,10 @@ public class UsbDeviceManager { updateUsbState(); updateAudioSourceFunction(); } + if (mConnected && mConfigured && mAccessoryStartPending) { + startAccessoryMode(); + mAccessoryStartPending = false; + } break; case MSG_ENABLE_ADB: setAdbEnabled(msg.arg1 == 1); @@ -661,6 +674,16 @@ public class UsbDeviceManager { mCurrentUser = msg.arg1; break; } + case MSG_START_ACCESSORY_MODE: + if (mConnected && mConfigured) { + startAccessoryMode(); + } else { + // we sometimes receive the kernel "accessory start" uevent + // before the "configured" uevent. In this case we need to defer + // handling this event until after we received the configured event + mAccessoryStartPending = true; + } + break; } } diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java index ff4857b..37b5c51 100644 --- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java @@ -27,6 +27,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; @@ -73,6 +74,7 @@ class UsbSettingsManager { private final UserHandle mUser; private final AtomicFile mSettingsFile; + private final boolean mDisablePermissionDialogs; private final Context mContext; private final Context mUserContext; @@ -510,6 +512,9 @@ class UsbSettingsManager { Environment.getUserSystemDirectory(user.getIdentifier()), "usb_device_manager.xml")); + mDisablePermissionDialogs = context.getResources().getBoolean( + com.android.internal.R.bool.config_disableUsbPermissionDialogs); + synchronized (mLock) { if (UserHandle.OWNER.equals(user)) { upgradeSingleUserLocked(); @@ -815,6 +820,14 @@ class UsbSettingsManager { (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { defaultRI = rInfo; } + + if (mDisablePermissionDialogs) { + // bypass dialog and launch the only matching activity + rInfo = matches.get(0); + if (rInfo.activityInfo != null) { + defaultPackage = rInfo.activityInfo.packageName; + } + } } if (defaultRI == null && defaultPackage != null) { @@ -970,7 +983,7 @@ class UsbSettingsManager { public boolean hasPermission(UsbDevice device) { synchronized (mLock) { int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID) { + if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { return true; } SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName()); @@ -984,7 +997,7 @@ class UsbSettingsManager { public boolean hasPermission(UsbAccessory accessory) { synchronized (mLock) { int uid = Binder.getCallingUid(); - if (uid == Process.SYSTEM_UID) { + if (uid == Process.SYSTEM_UID || mDisablePermissionDialogs) { return true; } SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index ff5c935..118cba4 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -335,6 +335,27 @@ public class MockPackageManager extends PackageManager { } @Override + public Drawable getActivityBanner(ComponentName activityName) + throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public Drawable getActivityBanner(Intent intent) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public Drawable getApplicationBanner(ApplicationInfo info) { + throw new UnsupportedOperationException(); + } + + @Override + public Drawable getApplicationBanner(String packageName) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override public Drawable getApplicationIcon(ApplicationInfo info) { throw new UnsupportedOperationException(); } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java index 208c387..5ba3ad9 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java @@ -8,7 +8,7 @@ import android.os.Bundle; import android.app.Activity; import android.util.AttributeSet; -import android.view.DisplayList; +import android.view.RenderNode; import android.view.View; import android.widget.LinearLayout; @@ -46,7 +46,7 @@ public class ProjectionActivity extends Activity { } private void setProject(boolean value) { - DisplayList displayList = getDisplayList(); + RenderNode displayList = getDisplayList(); if (displayList != null) { displayList.setProjectBackwards(value); } diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java index 7ff81e4..3114ca9 100644 --- a/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java +++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerActivity.java @@ -1,7 +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 com.android.onemedia; import android.app.Activity; +import android.media.session.MediaMetadata; +import android.media.session.PlaybackState; import android.os.Bundle; import android.util.Log; import android.view.Menu; @@ -79,10 +96,10 @@ public class OnePlayerActivity extends Activity { 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) { + if (mPlaybackState == PlaybackState.PLAYSTATE_PAUSED + || mPlaybackState == PlaybackState.PLAYSTATE_STOPPED) { mPlayer.play(); - } else if (mPlaybackState == Renderer.STATE_PLAYING) { + } else if (mPlaybackState == PlaybackState.PLAYSTATE_PLAYING) { mPlayer.pause(); } break; @@ -97,48 +114,55 @@ public class OnePlayerActivity extends Activity { private PlayerController.Listener mListener = new PlayerController.Listener() { @Override - public void onSessionStateChange(int state) { - mPlaybackState = state; + public void onPlaybackStateChange(PlaybackState state) { + mPlaybackState = state.getState(); boolean enablePlay = false; + StringBuilder statusBuilder = new StringBuilder(); switch (mPlaybackState) { - case Renderer.STATE_PLAYING: - mStatusView.setText("playing"); + case PlaybackState.PLAYSTATE_PLAYING: + statusBuilder.append("playing"); mPlayButton.setText("Pause"); enablePlay = true; break; - case Renderer.STATE_PAUSED: - mStatusView.setText("paused"); + case PlaybackState.PLAYSTATE_PAUSED: + statusBuilder.append("paused"); mPlayButton.setText("Play"); enablePlay = true; break; - case Renderer.STATE_ENDED: - mStatusView.setText("ended"); + case PlaybackState.PLAYSTATE_STOPPED: + statusBuilder.append("ended"); mPlayButton.setText("Play"); enablePlay = true; break; - case Renderer.STATE_ERROR: - mStatusView.setText("error"); + case PlaybackState.PLAYSTATE_ERROR: + statusBuilder.append("error: ").append(state.getErrorMessage()); break; - case Renderer.STATE_PREPARING: - mStatusView.setText("preparing"); + case PlaybackState.PLAYSTATE_BUFFERING: + statusBuilder.append("buffering"); break; - case Renderer.STATE_READY: - mStatusView.setText("ready"); - break; - case Renderer.STATE_STOPPED: - mStatusView.setText("stopped"); + case PlaybackState.PLAYSTATE_NONE: + statusBuilder.append("none"); break; + default: + statusBuilder.append(mPlaybackState); } + statusBuilder.append(" -- At position: ").append(state.getPosition()); + mStatusView.setText(statusBuilder.toString()); mPlayButton.setEnabled(enablePlay); } @Override - public void onPlayerStateChange(int state) { + public void onConnectionStateChange(int state) { if (state == PlayerController.STATE_DISCONNECTED) { setControlsEnabled(false); } else if (state == PlayerController.STATE_CONNECTED) { setControlsEnabled(true); } } + + @Override + public void onMetadataChange(MediaMetadata metadata) { + Log.d(TAG, "Metadata update! Title: " + metadata); + } }; } diff --git a/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java index 01610cd..573f7ff 100644 --- a/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java +++ b/tests/OneMedia/src/com/android/onemedia/OnePlayerService.java @@ -1,3 +1,18 @@ +/* + * 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.content.Context; @@ -5,9 +20,6 @@ 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"; diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerController.java b/tests/OneMedia/src/com/android/onemedia/PlayerController.java index 3f15db5..e831ec6 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerController.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerController.java @@ -1,8 +1,27 @@ +/* + * 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.session.MediaController; +import android.media.session.MediaMetadata; import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; +import android.media.session.TransportController; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -11,22 +30,23 @@ 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"; + private static final String TAG = "PlayerController"; public static final int STATE_DISCONNECTED = 0; public static final int STATE_CONNECTED = 1; protected MediaController mController; protected IPlayerService mBinder; + protected TransportController mTransportControls; private final Intent mServiceIntent; private Context mContext; private Listener mListener; + private TransportListener mTransportListener = new TransportListener(); private SessionCallback mControllerCb; private MediaSessionManager mManager; private Handler mHandler = new Handler(); @@ -52,7 +72,7 @@ public class PlayerController { Log.d(TAG, "Listener set to " + listener + " session is " + mController); if (mListener != null) { mHandler = new Handler(); - mListener.onPlayerStateChange( + mListener.onConnectionStateChange( mController == null ? STATE_DISCONNECTED : STATE_CONNECTED); } } @@ -70,11 +90,15 @@ public class PlayerController { } public void play() { - mController.sendMediaButton(KeyEvent.KEYCODE_MEDIA_PLAY); + if (mTransportControls != null) { + mTransportControls.play(); + } } public void pause() { - mController.sendMediaButton(KeyEvent.KEYCODE_MEDIA_PAUSE); + if (mTransportControls != null) { + mTransportControls.pause(); + } } public void setContent(String source) { @@ -113,10 +137,11 @@ public class PlayerController { } mBinder = null; mController = null; + mTransportControls = null; Log.d(TAG, "Disconnected from PlayerService"); if (mListener != null) { - mListener.onPlayerStateChange(STATE_DISCONNECTED); + mListener.onConnectionStateChange(STATE_DISCONNECTED); } } @@ -125,33 +150,60 @@ public class PlayerController { mBinder = IPlayerService.Stub.asInterface(service); Log.d(TAG, "service is " + service + " binder is " + mBinder); try { - mController = new MediaController(mBinder.getSessionToken()); + mController = MediaController.fromToken(mBinder.getSessionToken()); } catch (RemoteException e) { Log.e(TAG, "Error getting session", e); return; } mController.addCallback(mControllerCb, mHandler); + mTransportControls = mController.getTransportController(); + if (mTransportControls != null) { + mTransportControls.addStateListener(mTransportListener); + } Log.d(TAG, "Ready to use PlayerService"); if (mListener != null) { - mListener.onPlayerStateChange(STATE_CONNECTED); + mListener.onConnectionStateChange(STATE_CONNECTED); + if (mTransportControls != null) { + mListener.onPlaybackStateChange(mTransportControls.getPlaybackState()); + } } } }; private class SessionCallback extends MediaController.Callback { @Override - public void onPlaybackStateChange(int state) { + public void onRouteChanged(Bundle route) { + // TODO + } + } + + private class TransportListener extends TransportController.TransportStateListener { + @Override + public void onPlaybackStateChanged(PlaybackState state) { + if (state == null) { + return; + } + Log.d(TAG, "Received playback state change to state " + state.getState()); if (mListener != null) { - mListener.onSessionStateChange(state); + mListener.onPlaybackStateChange(state); } } + + @Override + public void onMetadataChanged(MediaMetadata metadata) { + if (metadata == null) { + return; + } + Log.d(TAG, "Received metadata change, title is " + + metadata.getString(MediaMetadata.METADATA_KEY_TITLE)); + } } public interface Listener { - public void onSessionStateChange(int state); - - public void onPlayerStateChange(int state); + public void onPlaybackStateChange(PlaybackState state); + public void onMetadataChange(MediaMetadata metadata); + public void onConnectionStateChange(int state); } } diff --git a/tests/OneMedia/src/com/android/onemedia/PlayerService.java b/tests/OneMedia/src/com/android/onemedia/PlayerService.java index 0b2ba8f..0ad6dd1 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerService.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerService.java @@ -1,11 +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 com.android.onemedia; import android.app.Service; import android.content.Intent; import android.media.session.MediaSessionToken; +import android.media.session.PlaybackState; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; +import android.util.Log; import com.android.onemedia.playback.IRequestCallback; import com.android.onemedia.playback.RequestUtils; @@ -18,14 +35,19 @@ public class PlayerService extends Service { private PlayerBinder mBinder; private PlayerSession mSession; private Intent mIntent; + private boolean mStarted = false; private ArrayList<IPlayerCallback> mCbs = new ArrayList<IPlayerCallback>(); @Override public void onCreate() { + Log.d(TAG, "onCreate"); mIntent = onCreateServiceIntent(); - mSession = onCreatePlayerController(); - mSession.createSession(); + if (mSession == null) { + mSession = onCreatePlayerController(); + mSession.createSession(); + mSession.setListener(mPlayerListener); + } } @Override @@ -38,12 +60,31 @@ public class PlayerService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "onStartCommand"); return START_STICKY; } @Override public void onDestroy() { + Log.d(TAG, "onDestroy"); mSession.onDestroy(); + mSession = null; + } + + public void onPlaybackStarted() { + if (!mStarted) { + Log.d(TAG, "Starting self"); + startService(onCreateServiceIntent()); + mStarted = true; + } + } + + public void onPlaybackEnded() { + if (mStarted) { + Log.d(TAG, "Stopping self"); + stopSelf(); + mStarted = false; + } } protected Intent onCreateServiceIntent() { @@ -58,6 +99,21 @@ public class PlayerService extends Service { return null; } + private final PlayerSession.Listener mPlayerListener = new PlayerSession.Listener() { + @Override + public void onPlayStateChanged(PlaybackState state) { + switch (state.getState()) { + case PlaybackState.PLAYSTATE_PLAYING: + onPlaybackStarted(); + break; + case PlaybackState.PLAYSTATE_STOPPED: + case PlaybackState.PLAYSTATE_ERROR: + onPlaybackEnded(); + break; + } + } + }; + public class PlayerBinder extends IPlayerService.Stub { @Override public void sendRequest(String action, Bundle params, IRequestCallback cb) { @@ -94,7 +150,6 @@ public class PlayerService extends Service { @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 index e5fb0d0..a2d7897 100644 --- a/tests/OneMedia/src/com/android/onemedia/PlayerSession.java +++ b/tests/OneMedia/src/com/android/onemedia/PlayerSession.java @@ -1,3 +1,18 @@ +/* + * 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.content.Context; @@ -5,6 +20,8 @@ import android.content.Intent; import android.media.session.MediaSession; import android.media.session.MediaSessionManager; import android.media.session.MediaSessionToken; +import android.media.session.PlaybackState; +import android.media.session.TransportPerformer; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; @@ -14,14 +31,18 @@ import com.android.onemedia.playback.Renderer; import com.android.onemedia.playback.RendererFactory; public class PlayerSession { - private static final String TAG = "PlayerController"; + private static final String TAG = "PlayerSession"; protected MediaSession mSession; protected Context mContext; protected RendererFactory mRendererFactory; protected LocalRenderer mRenderer; - protected ControllerCb mCallback; - protected RenderListener mRenderListener; + protected MediaSession.Callback mCallback; + protected Renderer.Listener mRenderListener; + protected TransportPerformer mPerformer; + + protected PlaybackState mPlaybackState; + protected Listener mListener; public PlayerSession(Context context) { mContext = context; @@ -29,6 +50,9 @@ public class PlayerSession { mRenderer = new LocalRenderer(context, null); mCallback = new ControllerCb(); mRenderListener = new RenderListener(); + mPlaybackState = new PlaybackState(); + mPlaybackState.setActions(PlaybackState.ACTION_PAUSE + | PlaybackState.ACTION_PLAY); mRenderer.registerListener(mRenderListener); } @@ -42,6 +66,10 @@ public class PlayerSession { Log.d(TAG, "Creating session for package " + mContext.getBasePackageName()); mSession = man.createSession("OneMedia"); mSession.addCallback(mCallback); + mPerformer = mSession.setTransportPerformerEnabled(); + mPerformer.addListener(new TransportListener()); + mPerformer.setPlaybackState(mPlaybackState); + mSession.publish(); } public void onDestroy() { @@ -54,6 +82,10 @@ public class PlayerSession { } } + public void setListener(Listener listener) { + mListener = listener; + } + public MediaSessionToken getSessionToken() { return mSession.getSessionToken(); } @@ -66,16 +98,58 @@ public class PlayerSession { mRenderer.setNextContent(request); } - protected class RenderListener implements Renderer.Listener { + public interface Listener { + public void onPlayStateChanged(PlaybackState state); + } + + private class RenderListener implements Renderer.Listener { @Override public void onError(int type, int extra, Bundle extras, Throwable error) { - mSession.setPlaybackState(Renderer.STATE_ERROR); + Log.d(TAG, "Sending onError with type " + type + " and extra " + extra); + mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR); + if (error != null) { + mPlaybackState.setErrorMessage(error.getLocalizedMessage()); + } + mPerformer.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } } @Override public void onStateChanged(int newState) { - mSession.setPlaybackState(newState); + if (newState != Renderer.STATE_ERROR) { + mPlaybackState.setErrorMessage(null); + } + switch (newState) { + case Renderer.STATE_ENDED: + case Renderer.STATE_STOPPED: + mPlaybackState.setState(PlaybackState.PLAYSTATE_STOPPED); + break; + case Renderer.STATE_INIT: + case Renderer.STATE_PREPARING: + mPlaybackState.setState(PlaybackState.PLAYSTATE_BUFFERING); + break; + case Renderer.STATE_ERROR: + mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR); + break; + case Renderer.STATE_PAUSED: + mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED); + break; + case Renderer.STATE_PLAYING: + mPlaybackState.setState(PlaybackState.PLAYSTATE_PLAYING); + break; + default: + mPlaybackState.setState(PlaybackState.PLAYSTATE_ERROR); + mPlaybackState.setErrorMessage("unkown state"); + break; + } + mPlaybackState.setPosition(mRenderer.getSeekPosition()); + mPerformer.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } } @Override @@ -84,7 +158,13 @@ public class PlayerSession { @Override public void onFocusLost() { - mSession.setPlaybackState(Renderer.STATE_PAUSED); + Log.d(TAG, "Focus lost, changing state to " + Renderer.STATE_PAUSED); + mPlaybackState.setState(PlaybackState.PLAYSTATE_PAUSED); + mPlaybackState.setPosition(mRenderer.getSeekPosition()); + mPerformer.setPlaybackState(mPlaybackState); + if (mListener != null) { + mListener.onPlayStateChanged(mPlaybackState); + } } @Override @@ -93,7 +173,7 @@ public class PlayerSession { } - protected class ControllerCb extends MediaSession.Callback { + private class ControllerCb extends MediaSession.Callback { @Override public void onMediaButton(Intent mediaRequestIntent) { @@ -114,4 +194,16 @@ public class PlayerSession { } } + private class TransportListener extends TransportPerformer.Listener { + @Override + public void onPlay() { + mRenderer.onPlay(); + } + + @Override + public void onPause() { + mRenderer.onPause(); + } + } + } diff --git a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java index 7493366..7f62f66 100644 --- a/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java +++ b/tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java @@ -499,11 +499,12 @@ public class LocalRenderer extends Renderer implements OnPreparedListener, @Override public boolean onPause() { MediaPlayer player = mPlayer; + // If the user paused us make sure we won't start playing again until + // asked to + mPlayOnReady = false; 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; } diff --git a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java index a39aba8..09531fd 100644 --- a/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java +++ b/tests/RenderThreadTest/src/com/example/renderthread/MainActivity.java @@ -7,7 +7,7 @@ import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; -import android.view.DisplayList; +import android.view.RenderNode; import android.view.HardwareRenderer; import android.view.ThreadedRenderer; import android.view.View; @@ -70,7 +70,7 @@ public class MainActivity extends Activity implements OnItemClickListener { private static final TimeInterpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); - DisplayList mDisplayList; + RenderNode mDisplayList; float mFromValue; float mDelta; long mDuration = DURATION * 2; diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java index 6666385..b235408 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java @@ -142,6 +142,13 @@ public final class Path_Delegate { } @LayoutlibDelegate + /*package*/ static boolean native_isConvex(long nPath) { + Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, + "Path.isConvex is not supported.", null, null); + return true; + } + + @LayoutlibDelegate /*package*/ static int native_getFillType(long nPath) { Path_Delegate pathDelegate = sManager.getDelegate(nPath); if (pathDelegate == null) { diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java index d40352f..b16b4aa 100644 --- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java +++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java @@ -18,6 +18,7 @@ package libcore.icu; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; import com.ibm.icu.text.DateTimePatternGenerator; +import com.ibm.icu.util.Currency; import com.ibm.icu.util.ULocale; import java.util.Locale; @@ -117,6 +118,11 @@ public class ICU_Delegate { } @LayoutlibDelegate + /*package*/ static int getCurrencyNumericCode(String currencyCode) { + return Currency.getInstance(currencyCode).getNumericCode(); + } + + @LayoutlibDelegate /*package*/ static String getCurrencySymbol(String locale, String currencyCode) { return ""; } @@ -231,7 +237,7 @@ public class ICU_Delegate { result.percent = '%'; result.perMill = '\u2030'; result.monetarySeparator = ' '; - result.minusSign = '-'; + result.minusSign = "-"; result.exponentSeparator = "e"; result.infinity = "\u221E"; result.NaN = "NaN"; |
