summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--api/current.txt189
-rw-r--r--api/system-current.txt15
-rw-r--r--api/test-current.txt152
-rw-r--r--cmds/screencap/screencap.cpp3
-rw-r--r--cmds/statsd/src/anomaly/subscriber_util.cpp2
-rw-r--r--cmds/statsd/src/atoms.proto45
-rw-r--r--cmds/statsd/src/external/Perfetto.cpp11
-rw-r--r--cmds/statsd/src/external/Perfetto.h1
-rw-r--r--core/java/android/app/ActivityManagerInternal.java3
-rw-r--r--core/java/android/app/ApplicationPackageManager.java10
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/role/RoleManager.java12
-rw-r--r--core/java/android/content/Intent.java61
-rw-r--r--core/java/android/content/pm/ILauncherApps.aidl1
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/LauncherApps.java20
-rw-r--r--core/java/android/content/pm/PackageManager.java77
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java11
-rw-r--r--core/java/android/content/pm/PackageUserState.java5
-rw-r--r--core/java/android/content/pm/PermissionInfo.java1
-rw-r--r--core/java/android/content/res/AssetManager.java34
-rw-r--r--core/java/android/content/res/Resources.java24
-rw-r--r--core/java/android/content/res/ResourcesImpl.java7
-rw-r--r--core/java/android/net/LinkProperties.java53
-rw-r--r--core/java/android/os/BugreportManager.java18
-rw-r--r--core/java/android/os/HwBinder.java2
-rw-r--r--core/java/android/os/HwBlob.java2
-rw-r--r--core/java/android/os/HwParcel.java2
-rw-r--r--core/java/android/os/IHwBinder.java2
-rw-r--r--core/java/android/os/IHwInterface.java3
-rw-r--r--core/java/android/os/NativeHandle.java2
-rw-r--r--core/java/android/os/Process.java5
-rw-r--r--core/java/android/provider/Settings.java2
-rw-r--r--core/java/android/text/util/Linkify.java79
-rw-r--r--core/java/android/view/textclassifier/ConversationAction.java266
-rw-r--r--core/java/android/view/textclassifier/ConversationActions.java432
-rw-r--r--core/java/android/view/textclassifier/TextClassificationConstants.java18
-rw-r--r--core/java/android/view/textclassifier/TextClassifier.java206
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java8
-rw-r--r--core/java/com/android/internal/app/procstats/ProcessStats.java53
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp76
-rw-r--r--core/jni/android/graphics/Graphics.cpp74
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h5
-rw-r--r--core/jni/android_os_Parcel.cpp2
-rw-r--r--core/jni/android_util_AssetManager.cpp55
-rw-r--r--core/jni/fd_utils.cpp1
-rw-r--r--core/proto/android/app/settings_enums.proto6
-rw-r--r--core/proto/android/service/package.proto1
-rw-r--r--core/proto/android/service/procstats.proto23
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/res/res/values/config.xml41
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java33
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java6
-rw-r--r--data/etc/Android.bp42
-rw-r--r--data/etc/com.android.carrierconfig.xml21
-rw-r--r--data/etc/com.android.contacts.xml22
-rw-r--r--data/etc/com.android.launcher3.xml23
-rw-r--r--data/etc/com.android.provision.xml21
-rw-r--r--data/etc/com.android.storagemanager.xml26
-rw-r--r--data/etc/com.android.systemui.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml29
-rw-r--r--graphics/java/android/graphics/BaseCanvas.java23
-rw-r--r--graphics/java/android/graphics/BaseRecordingCanvas.java20
-rw-r--r--graphics/java/android/graphics/Bitmap.java28
-rw-r--r--graphics/java/android/graphics/Canvas.java29
-rw-r--r--graphics/java/android/graphics/ColorSpace.java4
-rw-r--r--libs/androidfw/AssetManager2.cpp207
-rw-r--r--libs/androidfw/AttributeResolution.cpp2
-rw-r--r--libs/androidfw/CursorWindow.cpp2
-rw-r--r--libs/androidfw/LoadedArsc.cpp15
-rw-r--r--libs/androidfw/ResourceUtils.cpp61
-rw-r--r--libs/androidfw/ZipUtils.cpp2
-rw-r--r--libs/androidfw/include/androidfw/AssetDir.h2
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h50
-rw-r--r--libs/androidfw/include/androidfw/BackupHelpers.h4
-rw-r--r--libs/androidfw/include/androidfw/ConfigDescription.h2
-rw-r--r--libs/androidfw/include/androidfw/DisplayEventDispatcher.h2
-rw-r--r--libs/androidfw/include/androidfw/LoadedArsc.h2
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h12
-rw-r--r--libs/androidfw/include/androidfw/ResourceUtils.h12
-rw-r--r--libs/androidfw/include/androidfw/StringPiece.h4
-rw-r--r--libs/androidfw/include/androidfw/TypeWrappers.h2
-rw-r--r--libs/androidfw/include/androidfw/Util.h2
-rw-r--r--libs/androidfw/tests/AssetManager2_test.cpp107
-rw-r--r--libs/androidfw/tests/LoadedArsc_test.cpp8
-rw-r--r--libs/androidfw/tests/data/overlayable/overlayable.apkbin1387 -> 5523 bytes
-rw-r--r--libs/androidfw/tests/data/overlayable/res/values/overlayable.xml6
-rw-r--r--libs/hwui/DeviceInfo.cpp3
-rw-r--r--libs/hwui/private/hwui/DrawVkInfo.h13
-rw-r--r--libs/hwui/tests/unit/SkiaCanvasTests.cpp4
-rw-r--r--libs/hwui/utils/Color.cpp46
-rw-r--r--libs/hwui/utils/Color.h5
-rw-r--r--location/java/android/location/GnssMeasurement.java199
-rw-r--r--media/java/android/media/MediaCodec.java29
-rw-r--r--media/java/android/media/MediaConstants.java2
-rw-r--r--media/java/android/media/MediaController2.java13
-rw-r--r--media/java/android/media/MediaDrm.java281
-rw-r--r--media/java/android/media/MediaSession2.java20
-rw-r--r--media/java/android/media/Session2CommandGroup.java1
-rw-r--r--media/java/android/media/Session2Token.java19
-rw-r--r--media/jni/Android.bp3
-rw-r--r--media/jni/android_media_MediaCodec.cpp30
-rw-r--r--media/jni/android_media_MediaDrm.cpp54
-rw-r--r--native/android/Android.bp1
-rw-r--r--native/android/libandroid.map.txt13
-rw-r--r--native/android/sharedmem.cpp2
-rw-r--r--native/android/surface_control.cpp232
-rw-r--r--native/webview/plat_support/draw_fn.h11
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java13
-rw-r--r--packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java8
-rw-r--r--packages/NetworkStack/AndroidManifest.xml1
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java26
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java75
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml14
-rw-r--r--packages/SystemUI/res/values/dimens.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt24
-rw-r--r--packages/WallpaperCropper/Android.mk1
-rw-r--r--packages/WallpaperCropper/CleanSpec.mk50
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto7
-rw-r--r--services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java35
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java54
-rw-r--r--services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java10
-rw-r--r--services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java5
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java2
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java23
-rw-r--r--services/backup/java/com/android/server/backup/utils/AppBackupUtils.java9
-rw-r--r--services/backup/java/com/android/server/backup/utils/RestoreUtils.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java103
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java3
-rw-r--r--services/core/java/com/android/server/appop/HistoricalRegistry.java19
-rw-r--r--services/core/java/com/android/server/display/ColorDisplayService.java232
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java8
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java293
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java13
-rw-r--r--services/core/java/com/android/server/pm/Settings.java12
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java2
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java1
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java2
-rw-r--r--services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java13
-rw-r--r--services/core/java/com/android/server/signedconfig/SignatureVerifier.java45
-rw-r--r--services/core/java/com/android/server/signedconfig/SignedConfigEvent.java39
-rw-r--r--services/core/java/com/android/server/signedconfig/SignedConfigService.java36
-rw-r--r--services/core/java/com/android/server/slice/SlicePermissionManager.java20
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java16
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java3
-rw-r--r--services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java32
-rw-r--r--services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java3
-rw-r--r--services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java40
-rw-r--r--services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java13
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java5
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java73
-rw-r--r--services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java64
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java16
-rw-r--r--services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java25
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java22
-rw-r--r--startop/view_compiler/Android.bp6
-rw-r--r--telecomm/java/android/telecom/Connection.java15
-rw-r--r--telephony/java/android/telephony/PhoneStateListener.java2
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java37
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java9
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java63
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSession.java17
-rw-r--r--telephony/java/android/telephony/ims/ImsCallSessionListener.java13
-rw-r--r--telephony/java/android/telephony/ims/ImsStreamMediaProfile.java16
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl6
-rw-r--r--telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java6
-rw-r--r--telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl6
-rwxr-xr-xtelephony/java/com/android/internal/telephony/IOns.aidl4
-rwxr-xr-xtelephony/java/com/android/internal/telephony/ISub.aidl10
-rw-r--r--telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl31
-rw-r--r--tests/PackageWatchdog/Android.mk2
-rw-r--r--tests/net/java/android/net/LinkPropertiesTest.java45
-rw-r--r--tools/aapt2/Android.bp1
-rw-r--r--tools/aapt2/LoadedApk.cpp14
-rw-r--r--tools/aapt2/cmd/Optimize.cpp26
-rw-r--r--tools/aapt2/cmd/Optimize.h17
-rw-r--r--tools/aapt2/format/binary/BinaryResourceParser.cpp26
-rw-r--r--tools/aapt2/format/binary/TableFlattener.cpp170
-rw-r--r--tools/aapt2/format/binary/TableFlattener.h3
-rw-r--r--tools/aapt2/format/binary/TableFlattener_test.cpp110
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener.cpp112
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener.h44
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener_test.cpp67
-rw-r--r--tools/apilint/apilint.py34
-rw-r--r--tools/apilint/apilint_test.py43
-rw-r--r--tools/signedconfig/prod_public.pem5
-rwxr-xr-xtools/signedconfig/verify_b64.sh28
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java80
197 files changed, 4948 insertions, 1633 deletions
diff --git a/Android.bp b/Android.bp
index 7e97e66a9e80..c2024084d95d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1067,6 +1067,7 @@ java_library {
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/SystemApi.java",
+ "core/java/android/annotation/TestApi.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
diff --git a/api/current.txt b/api/current.txt
index 80fea7bf13ad..18f150fc57d8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11191,6 +11191,7 @@ package android.content.pm {
method public void registerCallback(android.content.pm.LauncherApps.Callback);
method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
+ method public boolean shouldHideFromSuggestions(java.lang.String, android.os.UserHandle);
method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
method public void startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
@@ -13736,6 +13737,7 @@ package android.graphics {
method public void drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint);
method public void drawTextRun(char[], int, int, int, int, float, float, boolean, android.graphics.Paint);
method public void drawTextRun(java.lang.CharSequence, int, int, int, int, float, float, boolean, android.graphics.Paint);
+ method public void drawTextRun(android.graphics.text.MeasuredText, int, int, int, int, float, float, boolean, android.graphics.Paint);
method public void drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint);
method public void enableZ();
method public boolean getClipBounds(android.graphics.Rect);
@@ -22662,6 +22664,7 @@ package android.location {
method public deprecated double getCarrierPhase();
method public deprecated double getCarrierPhaseUncertainty();
method public double getCn0DbHz();
+ method public int getCodeType();
method public int getConstellationType();
method public int getMultipathIndicator();
method public double getPseudorangeRateMetersPerSecond();
@@ -22677,6 +22680,7 @@ package android.location {
method public boolean hasCarrierFrequencyHz();
method public deprecated boolean hasCarrierPhase();
method public deprecated boolean hasCarrierPhaseUncertainty();
+ method public boolean hasCodeType();
method public boolean hasSnrInDb();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
@@ -22685,6 +22689,21 @@ package android.location {
field public static final int ADR_STATE_RESET = 2; // 0x2
field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
field public static final int ADR_STATE_VALID = 1; // 0x1
+ field public static final int CODE_TYPE_A = 0; // 0x0
+ field public static final int CODE_TYPE_B = 1; // 0x1
+ field public static final int CODE_TYPE_C = 2; // 0x2
+ field public static final int CODE_TYPE_CODELESS = 13; // 0xd
+ field public static final int CODE_TYPE_I = 3; // 0x3
+ field public static final int CODE_TYPE_L = 4; // 0x4
+ field public static final int CODE_TYPE_M = 5; // 0x5
+ field public static final int CODE_TYPE_P = 6; // 0x6
+ field public static final int CODE_TYPE_Q = 7; // 0x7
+ field public static final int CODE_TYPE_S = 8; // 0x8
+ field public static final int CODE_TYPE_UNKNOWN = -1; // 0xffffffff
+ field public static final int CODE_TYPE_W = 9; // 0x9
+ field public static final int CODE_TYPE_X = 10; // 0xa
+ field public static final int CODE_TYPE_Y = 11; // 0xb
+ field public static final int CODE_TYPE_Z = 12; // 0xc
field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2
@@ -24175,8 +24194,11 @@ package android.media {
public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
ctor public MediaCodec.CryptoException(int, java.lang.String);
method public int getErrorCode();
+ field public static final int ERROR_FRAME_TOO_LARGE = 8; // 0x8
field public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4
+ field public static final int ERROR_INSUFFICIENT_SECURITY = 7; // 0x7
field public static final int ERROR_KEY_EXPIRED = 2; // 0x2
+ field public static final int ERROR_LOST_STATE = 9; // 0x9
field public static final int ERROR_NO_KEY = 1; // 0x1
field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
field public static final int ERROR_SESSION_NOT_OPENED = 5; // 0x5
@@ -24517,6 +24539,22 @@ package android.media {
field public static final int REGULAR_CODECS = 0; // 0x0
}
+ public class MediaController2 implements java.lang.AutoCloseable {
+ ctor public MediaController2(android.content.Context, android.media.Session2Token);
+ ctor public MediaController2(android.content.Context, android.media.Session2Token, java.util.concurrent.Executor, android.media.MediaController2.ControllerCallback);
+ method public void cancelSessionCommand(java.lang.Object);
+ method public void close();
+ method public java.lang.Object sendSessionCommand(android.media.Session2Command, android.os.Bundle);
+ }
+
+ public static abstract class MediaController2.ControllerCallback {
+ ctor public MediaController2.ControllerCallback();
+ method public void onCommandResult(android.media.MediaController2, java.lang.Object, android.media.Session2Command, android.media.Session2Command.Result);
+ method public void onConnected(android.media.MediaController2, android.media.Session2CommandGroup);
+ method public void onDisconnected(android.media.MediaController2);
+ method public android.media.Session2Command.Result onSessionCommand(android.media.MediaController2, android.media.Session2Command, android.os.Bundle);
+ }
+
public final class MediaCrypto {
ctor public MediaCrypto(java.util.UUID, byte[]) throws android.media.MediaCryptoException;
method protected void finalize();
@@ -24624,6 +24662,7 @@ package android.media {
method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler);
+ method public void setOnSessionLostStateListener(android.media.MediaDrm.OnSessionLostStateListener, android.os.Handler);
method public void setPropertyByteArray(java.lang.String, byte[]);
method public void setPropertyString(java.lang.String, java.lang.String);
field public static final deprecated int EVENT_KEY_EXPIRED = 3; // 0x3
@@ -24742,6 +24781,10 @@ package android.media {
method public abstract void onKeyStatusChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
}
+ public static abstract interface MediaDrm.OnSessionLostStateListener {
+ method public abstract void onSessionLostState(android.media.MediaDrm, byte[]);
+ }
+
public static final class MediaDrm.ProvisionRequest {
method public byte[] getData();
method public java.lang.String getDefaultUrl();
@@ -24750,6 +24793,12 @@ package android.media {
public static abstract class MediaDrm.SecurityLevel implements java.lang.annotation.Annotation {
}
+ public static final class MediaDrm.SessionException extends java.lang.RuntimeException {
+ ctor public MediaDrm.SessionException(int, java.lang.String);
+ method public int getErrorCode();
+ field public static final int ERROR_RESOURCE_CONTENTION = 1; // 0x1
+ }
+
public class MediaDrmException extends java.lang.Exception {
ctor public MediaDrmException(java.lang.String);
}
@@ -25805,6 +25854,37 @@ package android.media {
method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
}
+ public class MediaSession2 implements java.lang.AutoCloseable {
+ method public void broadcastSessionCommand(android.media.Session2Command, android.os.Bundle);
+ method public void cancelSessionCommand(android.media.MediaSession2.ControllerInfo, java.lang.Object);
+ method public void close();
+ method public java.lang.String getSessionId();
+ method public android.media.Session2Token getSessionToken();
+ method public java.lang.Object sendSessionCommand(android.media.MediaSession2.ControllerInfo, android.media.Session2Command, android.os.Bundle);
+ }
+
+ public static final class MediaSession2.Builder {
+ ctor public MediaSession2.Builder(android.content.Context);
+ method public android.media.MediaSession2 build();
+ method public android.media.MediaSession2.Builder setId(java.lang.String);
+ method public android.media.MediaSession2.Builder setSessionActivity(android.app.PendingIntent);
+ method public android.media.MediaSession2.Builder setSessionCallback(java.util.concurrent.Executor, android.media.MediaSession2.SessionCallback);
+ }
+
+ public static final class MediaSession2.ControllerInfo {
+ method public java.lang.String getPackageName();
+ method public android.media.session.MediaSessionManager.RemoteUserInfo getRemoteUserInfo();
+ method public int getUid();
+ }
+
+ public static abstract class MediaSession2.SessionCallback {
+ ctor public MediaSession2.SessionCallback();
+ method public void onCommandResult(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, java.lang.Object, android.media.Session2Command, android.media.Session2Command.Result);
+ method public android.media.Session2CommandGroup onConnect(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
+ method public void onDisconnected(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo);
+ method public android.media.Session2Command.Result onSessionCommand(android.media.MediaSession2, android.media.MediaSession2.ControllerInfo, android.media.Session2Command, android.os.Bundle);
+ }
+
public final class MediaSync {
ctor public MediaSync();
method public android.view.Surface createInputSurface();
@@ -26118,6 +26198,19 @@ package android.media {
method public android.media.Session2CommandGroup.Builder removeCommand(int);
}
+ public final class Session2Token implements android.os.Parcelable {
+ ctor public Session2Token(android.content.Context, android.content.ComponentName);
+ method public int describeContents();
+ method public java.lang.String getPackageName();
+ method public java.lang.String getServiceName();
+ method public int getType();
+ method public int getUid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.media.Session2Token> CREATOR;
+ field public static final int TYPE_SESSION = 0; // 0x0
+ field public static final int TYPE_SESSION_SERVICE = 1; // 0x1
+ }
+
public class SoundPool {
ctor public deprecated SoundPool(int, int, int);
method public final void autoPause();
@@ -29649,8 +29742,10 @@ package android.net.wifi {
method public java.lang.String getMacAddress();
method public int getNetworkId();
method public int getRssi();
+ method public int getRxLinkSpeedMbps();
method public java.lang.String getSSID();
method public android.net.wifi.SupplicantState getSupplicantState();
+ method public int getTxLinkSpeedMbps();
method public void writeToParcel(android.os.Parcel, int);
field public static final java.lang.String FREQUENCY_UNITS = "MHz";
field public static final java.lang.String LINK_SPEED_UNITS = "Mbps";
@@ -43057,10 +43152,12 @@ package android.telecom {
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
+ field public static final java.lang.String EVENT_RTT_AUDIO_INDICATION_CHANGED = "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL = "android.telecom.extra.ANSWERING_DROPS_FG_CALL";
field public static final java.lang.String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME";
field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
+ field public static final java.lang.String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
field public static final java.lang.String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
@@ -45001,6 +45098,7 @@ package android.telephony.euicc {
}
public class EuiccManager {
+ method public android.telephony.euicc.EuiccManager createForCardId(int);
method public void deleteSubscription(int, android.app.PendingIntent);
method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent);
method public java.lang.String getEid();
@@ -47003,7 +47101,7 @@ package android.text.util {
public class Linkify {
ctor public Linkify();
method public static final boolean addLinks(android.text.Spannable, int);
- method public static final boolean addLinks(android.text.Spannable, int, android.text.util.Linkify.UrlSpanFactory);
+ method public static final boolean addLinks(android.text.Spannable, int, java.util.function.Function<java.lang.String, android.text.style.URLSpan>);
method public static final boolean addLinks(android.widget.TextView, int);
method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String);
method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
@@ -47011,7 +47109,7 @@ package android.text.util {
method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String);
method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
- method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, android.text.util.Linkify.UrlSpanFactory);
+ method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, java.util.function.Function<java.lang.String, android.text.style.URLSpan>);
field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2
field public static final deprecated int MAP_ADDRESSES = 8; // 0x8
@@ -47030,11 +47128,6 @@ package android.text.util {
method public abstract java.lang.String transformUrl(java.util.regex.Matcher, java.lang.String);
}
- public static class Linkify.UrlSpanFactory {
- ctor public Linkify.UrlSpanFactory();
- method public android.text.style.URLSpan create(java.lang.String);
- }
-
public class Rfc822Token {
ctor public Rfc822Token(java.lang.String, java.lang.String, java.lang.String);
method public java.lang.String getAddress();
@@ -52938,15 +53031,15 @@ package android.view.inspector {
package android.view.textclassifier {
- public final class ConversationActions implements android.os.Parcelable {
- ctor public ConversationActions(java.util.List<android.view.textclassifier.ConversationActions.ConversationAction>, java.lang.String);
+ public final class ConversationAction implements android.os.Parcelable {
method public int describeContents();
- method public java.util.List<android.view.textclassifier.ConversationActions.ConversationAction> getConversationActions();
- method public java.lang.String getId();
+ method public android.app.RemoteAction getAction();
+ method public float getConfidenceScore();
+ method public android.os.Bundle getExtras();
+ method public java.lang.CharSequence getTextReply();
+ method public java.lang.String getType();
method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions> CREATOR;
- field public static final java.lang.String HINT_FOR_IN_APP = "in_app";
- field public static final java.lang.String HINT_FOR_NOTIFICATION = "notification";
+ field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationAction> CREATOR;
field public static final java.lang.String TYPE_CALL_PHONE = "call_phone";
field public static final java.lang.String TYPE_CREATE_REMINDER = "create_reminder";
field public static final java.lang.String TYPE_OPEN_URL = "open_url";
@@ -52959,24 +53052,22 @@ package android.view.textclassifier {
field public static final java.lang.String TYPE_VIEW_MAP = "view_map";
}
- public static final class ConversationActions.ConversationAction implements android.os.Parcelable {
- method public int describeContents();
- method public android.app.RemoteAction getAction();
- method public float getConfidenceScore();
- method public android.os.Bundle getExtras();
- method public java.lang.CharSequence getTextReply();
- method public java.lang.String getType();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.ConversationAction> CREATOR;
+ public static final class ConversationAction.Builder {
+ ctor public ConversationAction.Builder(java.lang.String);
+ method public android.view.textclassifier.ConversationAction build();
+ method public android.view.textclassifier.ConversationAction.Builder setAction(android.app.RemoteAction);
+ method public android.view.textclassifier.ConversationAction.Builder setConfidenceScore(float);
+ method public android.view.textclassifier.ConversationAction.Builder setExtras(android.os.Bundle);
+ method public android.view.textclassifier.ConversationAction.Builder setTextReply(java.lang.CharSequence);
}
- public static final class ConversationActions.ConversationAction.Builder {
- ctor public ConversationActions.ConversationAction.Builder(java.lang.String);
- method public android.view.textclassifier.ConversationActions.ConversationAction build();
- method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setAction(android.app.RemoteAction);
- method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setConfidenceScore(float);
- method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setExtras(android.os.Bundle);
- method public android.view.textclassifier.ConversationActions.ConversationAction.Builder setTextReply(java.lang.CharSequence);
+ public final class ConversationActions implements android.os.Parcelable {
+ ctor public ConversationActions(java.util.List<android.view.textclassifier.ConversationAction>, java.lang.String);
+ method public int describeContents();
+ method public java.util.List<android.view.textclassifier.ConversationAction> getConversationActions();
+ method public java.lang.String getId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions> CREATOR;
}
public static final class ConversationActions.Message implements android.os.Parcelable {
@@ -53006,9 +53097,11 @@ package android.view.textclassifier {
method public java.lang.String getConversationId();
method public java.util.List<java.lang.String> getHints();
method public int getMaxSuggestions();
- method public android.view.textclassifier.ConversationActions.TypeConfig getTypeConfig();
+ method public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.Request> CREATOR;
+ field public static final java.lang.String HINT_FOR_IN_APP = "in_app";
+ field public static final java.lang.String HINT_FOR_NOTIFICATION = "notification";
}
public static final class ConversationActions.Request.Builder {
@@ -53017,23 +53110,7 @@ package android.view.textclassifier {
method public android.view.textclassifier.ConversationActions.Request.Builder setConversationId(java.lang.String);
method public android.view.textclassifier.ConversationActions.Request.Builder setHints(java.util.List<java.lang.String>);
method public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(int);
- method public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(android.view.textclassifier.ConversationActions.TypeConfig);
- }
-
- public static final class ConversationActions.TypeConfig implements android.os.Parcelable {
- method public int describeContents();
- method public java.util.Collection<java.lang.String> resolveTypes(java.util.Collection<java.lang.String>);
- method public boolean shouldIncludeTypesFromTextClassifier();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.view.textclassifier.ConversationActions.TypeConfig> CREATOR;
- }
-
- public static final class ConversationActions.TypeConfig.Builder {
- ctor public ConversationActions.TypeConfig.Builder();
- method public android.view.textclassifier.ConversationActions.TypeConfig build();
- method public android.view.textclassifier.ConversationActions.TypeConfig.Builder includeTypesFromTextClassifier(boolean);
- method public android.view.textclassifier.ConversationActions.TypeConfig.Builder setExcludedTypes(java.util.Collection<java.lang.String>);
- method public android.view.textclassifier.ConversationActions.TypeConfig.Builder setIncludedTypes(java.util.Collection<java.lang.String>);
+ method public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(android.view.textclassifier.TextClassifier.EntityConfig);
}
public final class SelectionEvent implements android.os.Parcelable {
@@ -53207,16 +53284,26 @@ package android.view.textclassifier {
}
public static final class TextClassifier.EntityConfig implements android.os.Parcelable {
- method public static android.view.textclassifier.TextClassifier.EntityConfig create(java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>);
- method public static android.view.textclassifier.TextClassifier.EntityConfig createWithExplicitEntityList(java.util.Collection<java.lang.String>);
- method public static android.view.textclassifier.TextClassifier.EntityConfig createWithHints(java.util.Collection<java.lang.String>);
+ method public static deprecated android.view.textclassifier.TextClassifier.EntityConfig create(java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>, java.util.Collection<java.lang.String>);
+ method public static deprecated android.view.textclassifier.TextClassifier.EntityConfig createWithExplicitEntityList(java.util.Collection<java.lang.String>);
+ method public static deprecated android.view.textclassifier.TextClassifier.EntityConfig createWithHints(java.util.Collection<java.lang.String>);
method public int describeContents();
method public java.util.Collection<java.lang.String> getHints();
method public java.util.Collection<java.lang.String> resolveEntityListModifications(java.util.Collection<java.lang.String>);
+ method public boolean shouldIncludeTypesFromTextClassifier();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifier.EntityConfig> CREATOR;
}
+ public static final class TextClassifier.EntityConfig.Builder {
+ ctor public TextClassifier.EntityConfig.Builder();
+ method public android.view.textclassifier.TextClassifier.EntityConfig build();
+ method public android.view.textclassifier.TextClassifier.EntityConfig.Builder includeTypesFromTextClassifier(boolean);
+ method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setExcludedTypes(java.util.Collection<java.lang.String>);
+ method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setHints(java.util.Collection<java.lang.String>);
+ method public android.view.textclassifier.TextClassifier.EntityConfig.Builder setIncludedTypes(java.util.Collection<java.lang.String>);
+ }
+
public final class TextClassifierEvent implements android.os.Parcelable {
method public int describeContents();
method public int[] getActionIndices();
diff --git a/api/system-current.txt b/api/system-current.txt
index 6c764b43e111..78f3471c3e86 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1047,7 +1047,6 @@ package android.app.role {
method public void removeRoleHolderAsUser(java.lang.String, java.lang.String, android.os.UserHandle, java.util.concurrent.Executor, android.app.role.RoleManagerCallback);
method public boolean removeRoleHolderFromController(java.lang.String, java.lang.String);
method public void setRoleNamesFromController(java.util.List<java.lang.String>);
- field public static final java.lang.String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";
}
public abstract interface RoleManagerCallback {
@@ -1254,6 +1253,7 @@ package android.content {
field public static final java.lang.String ACTION_INSTANT_APP_RESOLVER_SETTINGS = "android.intent.action.INSTANT_APP_RESOLVER_SETTINGS";
field public static final java.lang.String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION";
field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
+ field public static final java.lang.String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field public static final java.lang.String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
@@ -1284,11 +1284,12 @@ package android.content {
field public static final java.lang.String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
- field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
field public static final java.lang.String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME";
+ field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
+ field public static final java.lang.String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
field public static final java.lang.String EXTRA_UNKNOWN_INSTANT_APP = "android.intent.extra.UNKNOWN_INSTANT_APP";
field public static final java.lang.String EXTRA_VERIFICATION_BUNDLE = "android.intent.extra.VERIFICATION_BUNDLE";
field public static final java.lang.String METADATA_SETUP_VERSION = "android.SETUP_VERSION";
@@ -1461,6 +1462,7 @@ package android.content.pm {
method public abstract void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public void sendDeviceCustomizationReadyBroadcast();
method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int);
+ method public java.lang.String[] setDistractingPackageRestrictions(java.lang.String[], int);
method public void setHarmfulAppWarning(java.lang.String, java.lang.CharSequence);
method public deprecated java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, java.lang.String);
method public java.lang.String[] setPackagesSuspended(java.lang.String[], boolean, android.os.PersistableBundle, android.os.PersistableBundle, android.content.pm.SuspendDialogInfo);
@@ -1528,6 +1530,9 @@ package android.content.pm {
field public static final int MATCH_ANY_USER = 4194304; // 0x400000
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_INSTANT = 8388608; // 0x800000
+ field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1
+ field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2
+ field public static final int RESTRICTION_NONE = 0; // 0x0
}
public static abstract class PackageManager.DexModuleRegisterCallback {
@@ -1535,6 +1540,9 @@ package android.content.pm {
method public abstract void onDexModuleRegistered(java.lang.String, boolean, java.lang.String);
}
+ public static abstract class PackageManager.DistractionRestriction implements java.lang.annotation.Annotation {
+ }
+
public static abstract interface PackageManager.OnPermissionsChangedListener {
method public abstract void onPermissionsChanged(int);
}
@@ -7243,6 +7251,7 @@ package android.telephony.ims {
method public void callSessionInviteParticipantsRequestDelivered();
method public void callSessionInviteParticipantsRequestFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMayHandover(int, int);
+ method public void callSessionRttAudioIndicatorChanged(android.telephony.ims.ImsStreamMediaProfile);
method public void callSessionMergeComplete(android.telephony.ims.stub.ImsCallSessionImplBase);
method public void callSessionMergeFailed(android.telephony.ims.ImsReasonInfo);
method public void callSessionMergeStarted(android.telephony.ims.stub.ImsCallSessionImplBase, android.telephony.ims.ImsCallProfile);
@@ -7660,10 +7669,12 @@ package android.telephony.ims {
method public int describeContents();
method public int getAudioDirection();
method public int getAudioQuality();
+ method public boolean getRttAudioSpeech();
method public int getRttMode();
method public int getVideoDirection();
method public int getVideoQuality();
method public boolean isRttCall();
+ method public void setRttAudioSpeech(boolean);
method public void setRttMode(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int AUDIO_QUALITY_AMR = 1; // 0x1
diff --git a/api/test-current.txt b/api/test-current.txt
index 6d40e690b5e4..fb50fa194a92 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -421,6 +421,7 @@ package android.content.pm {
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
+ field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
@@ -500,6 +501,10 @@ package android.database.sqlite {
package android.graphics {
+ public final class Bitmap implements android.os.Parcelable {
+ method public void eraseColor(long);
+ }
+
public final class ImageDecoder implements java.lang.AutoCloseable {
method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
}
@@ -623,6 +628,7 @@ package android.location {
method public void resetCarrierFrequencyHz();
method public deprecated void resetCarrierPhase();
method public deprecated void resetCarrierPhaseUncertainty();
+ method public void resetCodeType();
method public void resetSnrInDb();
method public void set(android.location.GnssMeasurement);
method public void setAccumulatedDeltaRangeMeters(double);
@@ -634,6 +640,7 @@ package android.location {
method public deprecated void setCarrierPhase(double);
method public deprecated void setCarrierPhaseUncertainty(double);
method public void setCn0DbHz(double);
+ method public void setCodeType(int);
method public void setConstellationType(int);
method public void setMultipathIndicator(int);
method public void setPseudorangeRateMetersPerSecond(double);
@@ -790,6 +797,134 @@ package android.os {
method public static java.io.File getStorageDirectory();
}
+ public abstract class HwBinder implements android.os.IHwBinder {
+ ctor public HwBinder();
+ method public static final void configureRpcThreadpool(long, boolean);
+ method public static void enableInstrumentation();
+ method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String) throws java.util.NoSuchElementException, android.os.RemoteException;
+ method public static final android.os.IHwBinder getService(java.lang.String, java.lang.String, boolean) throws java.util.NoSuchElementException, android.os.RemoteException;
+ method public static final void joinRpcThreadpool();
+ method public abstract void onTransact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+ method public final void registerService(java.lang.String) throws android.os.RemoteException;
+ method public final void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+ }
+
+ public class HwBlob {
+ ctor public HwBlob(int);
+ method public final void copyToBoolArray(long, boolean[], int);
+ method public final void copyToDoubleArray(long, double[], int);
+ method public final void copyToFloatArray(long, float[], int);
+ method public final void copyToInt16Array(long, short[], int);
+ method public final void copyToInt32Array(long, int[], int);
+ method public final void copyToInt64Array(long, long[], int);
+ method public final void copyToInt8Array(long, byte[], int);
+ method public final boolean getBool(long);
+ method public final double getDouble(long);
+ method public final float getFloat(long);
+ method public final short getInt16(long);
+ method public final int getInt32(long);
+ method public final long getInt64(long);
+ method public final byte getInt8(long);
+ method public final java.lang.String getString(long);
+ method public final long handle();
+ method public final void putBlob(long, android.os.HwBlob);
+ method public final void putBool(long, boolean);
+ method public final void putBoolArray(long, boolean[]);
+ method public final void putDouble(long, double);
+ method public final void putDoubleArray(long, double[]);
+ method public final void putFloat(long, float);
+ method public final void putFloatArray(long, float[]);
+ method public final void putInt16(long, short);
+ method public final void putInt16Array(long, short[]);
+ method public final void putInt32(long, int);
+ method public final void putInt32Array(long, int[]);
+ method public final void putInt64(long, long);
+ method public final void putInt64Array(long, long[]);
+ method public final void putInt8(long, byte);
+ method public final void putInt8Array(long, byte[]);
+ method public final void putNativeHandle(long, android.os.NativeHandle);
+ method public final void putString(long, java.lang.String);
+ method public static java.lang.Boolean[] wrapArray(boolean[]);
+ method public static java.lang.Long[] wrapArray(long[]);
+ method public static java.lang.Byte[] wrapArray(byte[]);
+ method public static java.lang.Short[] wrapArray(short[]);
+ method public static java.lang.Integer[] wrapArray(int[]);
+ method public static java.lang.Float[] wrapArray(float[]);
+ method public static java.lang.Double[] wrapArray(double[]);
+ }
+
+ public class HwParcel {
+ ctor public HwParcel();
+ method public final void enforceInterface(java.lang.String);
+ method public final boolean readBool();
+ method public final java.util.ArrayList<java.lang.Boolean> readBoolVector();
+ method public final android.os.HwBlob readBuffer(long);
+ method public final double readDouble();
+ method public final java.util.ArrayList<java.lang.Double> readDoubleVector();
+ method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean);
+ method public final android.os.NativeHandle readEmbeddedNativeHandle(long, long);
+ method public final float readFloat();
+ method public final java.util.ArrayList<java.lang.Float> readFloatVector();
+ method public final short readInt16();
+ method public final java.util.ArrayList<java.lang.Short> readInt16Vector();
+ method public final int readInt32();
+ method public final java.util.ArrayList<java.lang.Integer> readInt32Vector();
+ method public final long readInt64();
+ method public final java.util.ArrayList<java.lang.Long> readInt64Vector();
+ method public final byte readInt8();
+ method public final java.util.ArrayList<java.lang.Byte> readInt8Vector();
+ method public final android.os.NativeHandle readNativeHandle();
+ method public final java.util.ArrayList<android.os.NativeHandle> readNativeHandleVector();
+ method public final java.lang.String readString();
+ method public final java.util.ArrayList<java.lang.String> readStringVector();
+ method public final android.os.IHwBinder readStrongBinder();
+ method public final void release();
+ method public final void releaseTemporaryStorage();
+ method public final void send();
+ method public final void verifySuccess();
+ method public final void writeBool(boolean);
+ method public final void writeBoolVector(java.util.ArrayList<java.lang.Boolean>);
+ method public final void writeBuffer(android.os.HwBlob);
+ method public final void writeDouble(double);
+ method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>);
+ method public final void writeFloat(float);
+ method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>);
+ method public final void writeInt16(short);
+ method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>);
+ method public final void writeInt32(int);
+ method public final void writeInt32Vector(java.util.ArrayList<java.lang.Integer>);
+ method public final void writeInt64(long);
+ method public final void writeInt64Vector(java.util.ArrayList<java.lang.Long>);
+ method public final void writeInt8(byte);
+ method public final void writeInt8Vector(java.util.ArrayList<java.lang.Byte>);
+ method public final void writeInterfaceToken(java.lang.String);
+ method public final void writeNativeHandle(android.os.NativeHandle);
+ method public final void writeNativeHandleVector(java.util.ArrayList<android.os.NativeHandle>);
+ method public final void writeStatus(int);
+ method public final void writeString(java.lang.String);
+ method public final void writeStringVector(java.util.ArrayList<java.lang.String>);
+ method public final void writeStrongBinder(android.os.IHwBinder);
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ }
+
+ public static abstract class HwParcel.Status implements java.lang.annotation.Annotation {
+ }
+
+ public abstract interface IHwBinder {
+ method public abstract boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long);
+ method public abstract android.os.IHwInterface queryLocalInterface(java.lang.String);
+ method public abstract void transact(int, android.os.HwParcel, android.os.HwParcel, int) throws android.os.RemoteException;
+ method public abstract boolean unlinkToDeath(android.os.IHwBinder.DeathRecipient);
+ }
+
+ public static abstract interface IHwBinder.DeathRecipient {
+ method public abstract void serviceDied(long);
+ }
+
+ public abstract interface IHwInterface {
+ method public abstract android.os.IHwBinder asBinder();
+ }
+
public class IncidentManager {
method public void reportIncident(android.os.IncidentReportArgs);
}
@@ -810,6 +945,18 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
+ public final class NativeHandle implements java.io.Closeable {
+ ctor public NativeHandle();
+ ctor public NativeHandle(java.io.FileDescriptor, boolean);
+ ctor public NativeHandle(java.io.FileDescriptor[], int[], boolean);
+ method public void close() throws java.io.IOException;
+ method public android.os.NativeHandle dup() throws java.io.IOException;
+ method public java.io.FileDescriptor getFileDescriptor();
+ method public java.io.FileDescriptor[] getFileDescriptors();
+ method public int[] getInts();
+ method public boolean hasSingleFileDescriptor();
+ }
+
public final class MessageQueue {
method public int postSyncBarrier();
method public void removeSyncBarrier(int);
@@ -825,6 +972,11 @@ package android.os {
public class Process {
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
+ field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90
+ field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
+ field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7
+ field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
+ field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
}
public final class RemoteCallback implements android.os.Parcelable {
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 8fa298060d60..3d74f8b207af 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -81,8 +81,7 @@ static sk_sp<SkColorSpace> dataSpaceToColorSpace(ui::Dataspace d)
case ui::Dataspace::V0_SRGB:
return SkColorSpace::MakeSRGB();
case ui::Dataspace::DISPLAY_P3:
- return SkColorSpace::MakeRGB(
- SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
default:
return nullptr;
}
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index 9d37cdb2d4d7..ad5eae361f1c 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -57,7 +57,7 @@ void triggerSubscribers(const int64_t rule_id,
break;
case Subscription::SubscriberInformationCase::kPerfettoDetails:
if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details(),
- rule_id, configKey)) {
+ subscription.id(), rule_id, configKey)) {
ALOGW("Failed to generate perfetto traces.");
}
break;
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 860e40d67435..0fa7cffa07af 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -181,6 +181,7 @@ message Atom {
DocsUISearchTypeReported docs_ui_search_type_reported = 120;
DataStallEvent data_stall_event = 121;
RescuePartyResetReported rescue_party_reset_reported = 122;
+ SignedConfigReported signed_config_reported = 123;
}
// Pulled events will start at field 10000.
@@ -3802,7 +3803,7 @@ message NetworkDnsEventReported {
//bionic/libc/include/netdb.h
//system/netd/resolv/include/netd_resolv/resolv.h
enum ReturnCode {
- EAI_NO_ERR = 0;
+ EAI_NO_ERROR = 0;
EAI_ADDRFAMILY = 1;
EAI_AGAIN = 2;
EAI_BADFLAGS = 3;
@@ -3859,3 +3860,45 @@ message RescuePartyResetReported {
// The rescue level of this reset. A value of 0 indicates missing or unknown level information.
optional int32 rescue_level = 1;
}
+
+/**
+ * Logs when signed config is received from an APK, and if that config was applied successfully.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+ */
+message SignedConfigReported {
+ enum Type {
+ UNKNOWN_TYPE = 0;
+ GLOBAL_SETTINGS = 1;
+ }
+ optional Type type = 1;
+
+ // The final status of the signed config received.
+ enum Status {
+ UNKNOWN_STATUS = 0;
+ APPLIED = 1;
+ BASE64_FAILURE_CONFIG = 2;
+ BASE64_FAILURE_SIGNATURE = 3;
+ SECURITY_EXCEPTION = 4;
+ INVALID_CONFIG = 5;
+ OLD_CONFIG = 6;
+ SIGNATURE_CHECK_FAILED = 7;
+ NOT_APPLICABLE = 8;
+ SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT = 9;
+ }
+ optional Status status = 2;
+
+ // The version of the signed config processed.
+ optional int32 version = 3;
+
+ // The package name that the config was extracted from.
+ optional string from_package = 4;
+
+ enum Key {
+ NO_KEY = 0;
+ DEBUG = 1;
+ PRODUCTION = 2;
+ }
+ // Which key was used to verify the config.
+ optional Key verified_with = 5;
+}
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index 42cc543f18a8..0c4c3301e61e 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -39,6 +39,7 @@ namespace os {
namespace statsd {
bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+ int64_t subscription_id,
int64_t alert_id,
const ConfigKey& configKey) {
VLOG("Starting trace collection through perfetto");
@@ -48,9 +49,11 @@ bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
return false;
}
- char alertId[20];
- char configId[20];
- char configUid[20];
+ char subscriptionId[25];
+ char alertId[25];
+ char configId[25];
+ char configUid[25];
+ snprintf(subscriptionId, sizeof(subscriptionId), "%" PRId64, subscription_id);
snprintf(alertId, sizeof(alertId), "%" PRId64, alert_id);
snprintf(configId, sizeof(configId), "%" PRId64, configKey.GetId());
snprintf(configUid, sizeof(configUid), "%d", configKey.GetUid());
@@ -94,7 +97,7 @@ bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
execl("/system/bin/perfetto", "perfetto", "--background", "--config", "-", "--dropbox",
kDropboxTag, "--alert-id", alertId, "--config-id", configId, "--config-uid",
- configUid, nullptr);
+ configUid, "--subscription-id", subscriptionId, nullptr);
// execl() doesn't return in case of success, if we get here something
// failed.
diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h
index 1e7f728e1357..ab2c1954e2a0 100644
--- a/cmds/statsd/src/external/Perfetto.h
+++ b/cmds/statsd/src/external/Perfetto.h
@@ -32,6 +32,7 @@ class PerfettoDetails; // Declared in statsd_config.pb.h
// This method returns immediately after passing the config and does NOT wait
// for the full duration of the trace.
bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config,
+ int64_t subscription_id,
int64_t alert_id,
const ConfigKey& configKey);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c90e40411240..1f01e2698fb5 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -317,4 +317,7 @@ public abstract class ActivityManagerInternal {
/** Returns true if the given uid is the app in the foreground. */
public abstract boolean isAppForeground(int uid);
+
+ /** Remove pending backup for the given userId. */
+ public abstract void clearPendingBackup(int userId);
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 94983e1c3672..9bcb36f28d17 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2276,6 +2276,16 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
+ public String[] setDistractingPackageRestrictions(String[] packages, int distractionFlags) {
+ try {
+ return mPM.setDistractingPackageRestrictionsAsUser(packages, distractionFlags,
+ mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
String dialogMessage) {
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 347973ea3387..fb65da14a087 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -317,7 +317,6 @@ interface IActivityManager {
*/
void requestWifiBugReport(in String shareTitle, in String shareDescription);
- void clearPendingBackup();
Intent getIntentForIntentSender(in IIntentSender sender);
// This is not public because you need to be very careful in how you
// manage your activity to make sure it is always the uid you expect.
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 27581fc0088a..a6abe0b30f79 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -179,16 +179,6 @@ public final class RoleManager {
public static final String ACTION_REQUEST_ROLE = "android.app.role.action.REQUEST_ROLE";
/**
- * The name of the requested role.
- * <p>
- * <strong>Type:</strong> String
- *
- * @hide
- */
- @SystemApi
- public static final String EXTRA_REQUEST_ROLE_NAME = "android.app.role.extra.REQUEST_ROLE_NAME";
-
- /**
* The permission required to manage records of role holders in {@link RoleManager} directly.
*
* @hide
@@ -236,7 +226,7 @@ public final class RoleManager {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Intent intent = new Intent(ACTION_REQUEST_ROLE);
intent.setPackage(mContext.getPackageManager().getPermissionControllerPackageName());
- intent.putExtra(EXTRA_REQUEST_ROLE_NAME, roleName);
+ intent.putExtra(Intent.EXTRA_ROLE_NAME, roleName);
return intent;
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e37126b8c2e7..d27cce535c3b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1833,6 +1833,37 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.action.REVIEW_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage a default app.
+ * <p>
+ * Input: {@link #EXTRA_ROLE_NAME} specifies the role of the default app which will be managed
+ * by the launched UI.
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ @SystemApi
+ public static final String ACTION_MANAGE_DEFAULT_APP =
+ "android.intent.action.MANAGE_DEFAULT_APP";
+
+ /**
+ * Intent extra: A role name.
+ * <p>
+ * Type: String
+ * </p>
+ *
+ * @see android.app.role.RoleManager
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
+
+ /**
* Activity action: Launch UI to manage special app accesses.
* <p>
* Input: Nothing.
@@ -2411,6 +2442,25 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_PACKAGES_UNSUSPENDED = "android.intent.action.PACKAGES_UNSUSPENDED";
/**
+ * Broadcast Action: Distracting packages have been changed.
+ * <p>Includes the following extras:
+ * <ul>
+ * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages which have been changed.
+ * <li> {@link #EXTRA_CHANGED_UID_LIST} is the set of uids which have been changed.
+ * <li> {@link #EXTRA_DISTRACTION_RESTRICTIONS} the new restrictions set on these packages.
+ * </ul>
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system. It is only sent to registered receivers.
+ *
+ * @see PackageManager#setDistractingPackageRestrictions(String[], int)
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DISTRACTING_PACKAGES_CHANGED =
+ "android.intent.action.DISTRACTING_PACKAGES_CHANGED";
+
+ /**
* Broadcast Action: Sent to a package that has been suspended by the system. This is sent
* whenever a package is put into a suspended state or any of its app extras change while in the
* suspended state.
@@ -5120,6 +5170,17 @@ public class Intent implements Parcelable, Cloneable {
"android.intent.extra.changed_uid_list";
/**
+ * An integer denoting a bitwise combination of restrictions set on distracting packages via
+ * {@link PackageManager#setDistractingPackageRestrictions(String[], int)}
+ *
+ * @hide
+ * @see PackageManager.DistractionRestriction
+ * @see PackageManager#setDistractingPackageRestrictions(String[], int)
+ */
+ public static final String EXTRA_DISTRACTION_RESTRICTIONS =
+ "android.intent.extra.distraction_restrictions";
+
+ /**
* @hide
* Magic extra system code can use when binding, to give a label for
* who it is that has bound to a service. This is an integer giving
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index ba7710b8ef48..db2b6fd235d3 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -69,6 +69,7 @@ interface ILauncherApps {
int userId);
boolean hasShortcutHostPermission(String callingPackage);
+ boolean shouldHideFromSuggestions(String packageName, in UserHandle user);
ParceledListSlice getShortcutConfigActivities(
String callingPackage, String packageName, in UserHandle user);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 64a4479be7ee..d5c3b26b094d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -273,6 +273,9 @@ interface IPackageManager {
void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
+ String[] setDistractingPackageRestrictionsAsUser(in String[] packageNames, int restrictionFlags,
+ int userId);
+
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
in SuspendDialogInfo dialogInfo, String callingPackage, int userId);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 44e652f10094..983ea9f847cd 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -697,6 +697,26 @@ public class LauncherApps {
}
/**
+ * Returns whether a package should be hidden from suggestions to the user. Currently, this
+ * could be done because the package was marked as distracting to the user via
+ * {@code PackageManager.setDistractingPackageRestrictions(String[], int)}.
+ *
+ * @param packageName The package for which to check.
+ * @param user the {@link UserHandle} of the profile.
+ * @return
+ */
+ public boolean shouldHideFromSuggestions(@NonNull String packageName,
+ @NonNull UserHandle user) {
+ Preconditions.checkNotNull(packageName, "packageName");
+ Preconditions.checkNotNull(user, "user");
+ try {
+ return mService.shouldHideFromSuggestions(packageName, user);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns {@link ApplicationInfo} about an application installed for a specific user profile.
*
* @param packageName The package name of the application
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2aeb68da365b..636a70f040da 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5889,6 +5889,74 @@ public abstract class PackageManager {
public abstract boolean isSignedByExactly(String packageName, KeySet ks);
/**
+ * Flag to denote no restrictions. This should be used to clear any restrictions that may have
+ * been previously set for the package.
+ * @see PackageManager.DistractionRestriction
+ * @hide
+ */
+ @SystemApi
+ public static final int RESTRICTION_NONE = 0x0;
+
+ /**
+ * Flag to denote that a package should be hidden from any suggestions to the user.
+ * @see PackageManager.DistractionRestriction
+ * @hide
+ */
+ @SystemApi
+ public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 0x00000001;
+
+ /**
+ * Flag to denote that a package's notifications should be hidden.
+ * @see PackageManager.DistractionRestriction
+ * @hide
+ */
+ @SystemApi
+ public static final int RESTRICTION_HIDE_NOTIFICATIONS = 0x00000002;
+
+ /**
+ * Restriction flags to set on a package that is considered as distracting to the user.
+ * These should help the user to restrict their usage of these apps.
+ *
+ * @see #setDistractingPackageRestrictions(String[], int)
+ * @hide
+ */
+ @SystemApi
+ @IntDef(flag = true, prefix = {"RESTRICTION_"}, value = {
+ RESTRICTION_NONE,
+ RESTRICTION_HIDE_FROM_SUGGESTIONS,
+ RESTRICTION_HIDE_NOTIFICATIONS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DistractionRestriction {}
+
+ /**
+ * Mark or unmark the given packages as distracting to the user.
+ * These packages can have certain restrictions set that should discourage the user to launch
+ * them often. For example, notifications from such an app can be hidden, or the app can be
+ * removed from launcher suggestions, so the user is able to restrict their use of these apps.
+ *
+ * <p>The caller must hold {@link android.Manifest.permission#SUSPEND_APPS} to use this API.
+ *
+ * @param packages Packages to mark as distracting.
+ * @param restrictionFlags Any combination of {@link DistractionRestriction restrictions} to
+ * impose on the given packages. {@link #RESTRICTION_NONE} can be used
+ * to clear any existing restrictions.
+ * @return A list of packages that could not have the {@code restrictionFlags} set. The system
+ * may prevent restricting critical packages to preserve normal device function.
+ *
+ * @see DistractionRestriction
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.SUSPEND_APPS)
+ @NonNull
+ public String[] setDistractingPackageRestrictions(@NonNull String[] packages,
+ @DistractionRestriction int restrictionFlags) {
+ throw new UnsupportedOperationException(
+ "setDistractingPackageRestrictions not implemented");
+ }
+
+ /**
* Puts the package in a suspended state, where attempts at starting activities are denied.
*
* <p>It doesn't remove the data or the actual package file. The application's notifications
@@ -5911,8 +5979,7 @@ public abstract class PackageManager {
* {@link PersistableBundle} objects to be shared with the apps being suspended and the
* launcher to support customization that they might need to handle the suspended state.
*
- * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} or
- * {@link Manifest.permission#MANAGE_USERS} to use this api.</p>
+ * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this API.
*
* @param packageNames The names of the packages to set the suspended status.
* @param suspended If set to {@code true}, the packages will be suspended, if set to
@@ -5955,7 +6022,7 @@ public abstract class PackageManager {
* <p>When the user tries to launch a suspended app, a system dialog alerting them that the app
* is suspended will be shown instead.
* The caller can optionally customize the dialog by passing a {@link SuspendDialogInfo} object
- * to this api. This dialog will have a button that starts the
+ * to this API. This dialog will have a button that starts the
* {@link Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} intent if the suspending app declares an
* activity which handles this action.
*
@@ -5966,7 +6033,7 @@ public abstract class PackageManager {
* {@link PersistableBundle} objects to be shared with the apps being suspended and the
* launcher to support customization that they might need to handle the suspended state.
*
- * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this api.
+ * <p>The caller must hold {@link Manifest.permission#SUSPEND_APPS} to use this API.
*
* @param packageNames The names of the packages to set the suspended status.
* @param suspended If set to {@code true}, the packages will be suspended, if set to
@@ -6005,7 +6072,7 @@ public abstract class PackageManager {
* #setPackagesSuspended(String[], boolean, PersistableBundle, PersistableBundle,
* SuspendDialogInfo) setPackagesSuspended}. The platform prevents suspending certain critical
* packages to keep the device in a functioning state, e.g. the default dialer.
- * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this api.
+ * Apps need to hold {@link Manifest.permission#SUSPEND_APPS SUSPEND_APPS} to call this API.
*
* <p>
* Note that this set of critical packages can change with time, so even though a package name
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 83979e925be1..83563d0fd9f6 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -284,6 +284,17 @@ public abstract class PackageManagerInternal {
public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage, int userId);
/**
+ * Gets any distraction flags set via
+ * {@link PackageManager#setDistractingPackageRestrictions(String[], int)}
+ *
+ * @param packageName
+ * @param userId
+ * @return A bitwise OR of any of the {@link PackageManager.DistractionRestriction}
+ */
+ public abstract @PackageManager.DistractionRestriction int getDistractingPackageRestrictions(
+ String packageName, int userId);
+
+ /**
* Do a straight uid lookup for the given package/application in the given user.
* @see PackageManager#getPackageUidAsUser(String, int, int)
* @return The app's uid, or < 0 if the package was not found in that user
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 74dd08fc1d6b..249b6919fc28 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -54,6 +54,7 @@ public class PackageUserState {
public boolean stopped;
public boolean notLaunched;
public boolean hidden; // Is the app restricted by owner / admin
+ public int distractionFlags;
public boolean suspended;
public String suspendingPackage;
public SuspendDialogInfo dialogInfo;
@@ -92,6 +93,7 @@ public class PackageUserState {
stopped = o.stopped;
notLaunched = o.notLaunched;
hidden = o.hidden;
+ distractionFlags = o.distractionFlags;
suspended = o.suspended;
suspendingPackage = o.suspendingPackage;
dialogInfo = o.dialogInfo;
@@ -222,6 +224,9 @@ public class PackageUserState {
if (hidden != oldState.hidden) {
return false;
}
+ if (distractionFlags != oldState.distractionFlags) {
+ return false;
+ }
if (suspended != oldState.suspended) {
return false;
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index bb8c92dba71a..a3395ac9fd13 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -158,6 +158,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
* @hide
*/
@SystemApi
+ @TestApi
public static final int PROTECTION_FLAG_OEM = 0x4000;
/**
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index f1a4db25cd14..9e0a9ba0dc7b 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -732,6 +732,38 @@ public final class AssetManager implements AutoCloseable {
}
}
+ /**
+ * Enable resource resolution logging to track the steps taken to resolve the last resource
+ * entry retrieved. Stores the configuration and package names for each step.
+ *
+ * Default disabled.
+ *
+ * @param enabled Boolean indicating whether to enable or disable logging.
+ *
+ * @hide
+ */
+ public void setResourceResolutionLoggingEnabled(boolean enabled) {
+ synchronized (this) {
+ ensureValidLocked();
+ nativeSetResourceResolutionLoggingEnabled(mObject, enabled);
+ }
+ }
+
+ /**
+ * Retrieve the last resource resolution path logged.
+ *
+ * @return Formatted string containing last resource ID/name and steps taken to resolve final
+ * entry, including configuration and package names.
+ *
+ * @hide
+ */
+ public @Nullable String getLastResourceResolution() {
+ synchronized (this) {
+ ensureValidLocked();
+ return nativeGetLastResourceResolution(mObject);
+ }
+ }
+
CharSequence getPooledStringForCookie(int cookie, int id) {
// Cookies map to ApkAssets starting at 1.
return getApkAssets()[cookie - 1].getStringFromPool(id);
@@ -1383,6 +1415,8 @@ public final class AssetManager implements AutoCloseable {
private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
+ private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled);
+ private static native @Nullable String nativeGetLastResourceResolution(long ptr);
// Style attribute retrieval native methods.
private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 365ceac68ee1..c4b315ec90c8 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -2010,22 +2010,36 @@ public class Resources {
public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
return mResourcesImpl.getResourceTypeName(resid);
}
-
+
/**
* Return the entry name for a given resource identifier.
- *
+ *
* @param resid The resource identifier whose entry name is to be
* retrieved.
- *
+ *
* @return A string holding the entry name of the resource.
- *
+ *
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
- *
+ *
* @see #getResourceName
*/
public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
return mResourcesImpl.getResourceEntryName(resid);
}
+
+ /**
+ * Return formatted log of the last retrieved resource's resolution path.
+ *
+ * @return A string holding a formatted log of the steps taken to resolve the last resource.
+ *
+ * @throws NotFoundException Throws NotFoundException if there hasn't been a resource
+ * resolved yet.
+ *
+ * @hide
+ */
+ public String getLastResourceResolution() throws NotFoundException {
+ return mResourcesImpl.getLastResourceResolution();
+ }
/**
* Parse a series of {@link android.R.styleable#Extra &lt;extra&gt;} tags from
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 2ad4f625ef8c..77796d9ebdf5 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -299,6 +299,13 @@ public class ResourcesImpl {
}
@NonNull
+ String getLastResourceResolution() throws NotFoundException {
+ String str = mAssets.getLastResourceResolution();
+ if (str != null) return str;
+ throw new NotFoundException("Associated AssetManager hasn't resolved a resource");
+ }
+
+ @NonNull
CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
PluralRules rule = getPluralRule();
CharSequence res = mAssets.getResourceBagText(id,
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 4a466f300718..617125b3f904 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -66,6 +66,7 @@ public final class LinkProperties implements Parcelable {
private int mMtu;
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
private String mTcpBufferSizes;
+ private IpPrefix mNat64Prefix;
private static final int MIN_MTU = 68;
private static final int MIN_MTU_V6 = 1280;
@@ -760,6 +761,32 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Returns the NAT64 prefix in use on this link, if any.
+ *
+ * @return the NAT64 prefix.
+ * @hide
+ */
+ public @Nullable IpPrefix getNat64Prefix() {
+ return mNat64Prefix;
+ }
+
+ /**
+ * Sets the NAT64 prefix in use on this link.
+ *
+ * Currently, only 96-bit prefixes (i.e., where the 32-bit IPv4 address is at the end of the
+ * 128-bit IPv6 address) are supported.
+ *
+ * @param prefix the NAT64 prefix.
+ * @hide
+ */
+ public void setNat64Prefix(IpPrefix prefix) {
+ if (prefix != null && prefix.getPrefixLength() != 96) {
+ throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
+ }
+ mNat64Prefix = prefix; // IpPrefix objects are immutable.
+ }
+
+ /**
* Adds a stacked link.
*
* If there is already a stacked link with the same interface name as link,
@@ -831,6 +858,7 @@ public final class LinkProperties implements Parcelable {
mStackedLinks.clear();
mMtu = 0;
mTcpBufferSizes = null;
+ mNat64Prefix = null;
}
/**
@@ -908,6 +936,11 @@ public final class LinkProperties implements Parcelable {
resultJoiner.add(mHttpProxy.toString());
}
+ if (mNat64Prefix != null) {
+ resultJoiner.add("Nat64Prefix:");
+ resultJoiner.add(mNat64Prefix.toString());
+ }
+
final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
if (!stackedLinksValues.isEmpty()) {
final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
@@ -1295,6 +1328,17 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Compares this {@code LinkProperties} NAT64 prefix against the target.
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalNat64Prefix(LinkProperties target) {
+ return Objects.equals(mNat64Prefix, target.mNat64Prefix);
+ }
+
+ /**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
* all their fields are equal in values.
@@ -1330,7 +1374,8 @@ public final class LinkProperties implements Parcelable {
&& isIdenticalHttpProxy(target)
&& isIdenticalStackedLinks(target)
&& isIdenticalMtu(target)
- && isIdenticalTcpBufferSizes(target);
+ && isIdenticalTcpBufferSizes(target)
+ && isIdenticalNat64Prefix(target);
}
/**
@@ -1443,7 +1488,8 @@ public final class LinkProperties implements Parcelable {
+ ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
+ (mUsePrivateDns ? 57 : 0)
+ mPcscfs.size() * 67
- + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode());
+ + ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
+ + Objects.hash(mNat64Prefix);
}
/**
@@ -1484,6 +1530,8 @@ public final class LinkProperties implements Parcelable {
} else {
dest.writeByte((byte)0);
}
+ dest.writeParcelable(mNat64Prefix, 0);
+
ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
dest.writeList(stackedLinks);
}
@@ -1535,6 +1583,7 @@ public final class LinkProperties implements Parcelable {
if (in.readByte() == 1) {
netProp.setHttpProxy(in.readParcelable(null));
}
+ netProp.setNat64Prefix(in.readParcelable(null));
ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
in.readList(stackedLinks, LinkProperties.class.getClassLoader());
for (LinkProperties stackedLink: stackedLinks) {
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 1343d24d0d94..b15a4d3170b3 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -114,7 +114,6 @@ public class BugreportManager {
}
}
-
// TODO(b/111441001) Connect up with BugreportListener methods.
private final class DumpstateListener extends IDumpstateListener.Stub
implements DeathRecipient {
@@ -130,6 +129,23 @@ public class BugreportManager {
}
@Override
+ public void onProgress(int progress) throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
+ public void onError(int errorCode) throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
+ public void onFinished(long durationMs, String title, String description)
+ throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ // Old methods; should go away
+ @Override
public void onProgressUpdated(int progress) throws RemoteException {
// TODO(b/111441001): implement
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 3de3494e7ea7..9e3e83e14a48 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import libcore.util.NativeAllocationRegistry;
@@ -24,6 +25,7 @@ import java.util.NoSuchElementException;
/** @hide */
@SystemApi
+@TestApi
public abstract class HwBinder implements IHwBinder {
private static final String TAG = "HwBinder";
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 6a5bb1c0a988..0ec63b5815f1 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import libcore.util.NativeAllocationRegistry;
@@ -28,6 +29,7 @@ import libcore.util.NativeAllocationRegistry;
* @hide
*/
@SystemApi
+@TestApi
public class HwBlob {
private static final String TAG = "HwBlob";
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 7a51db2dc5f9..7919a00166bf 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.IntDef;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import libcore.util.NativeAllocationRegistry;
@@ -28,6 +29,7 @@ import java.util.Arrays;
/** @hide */
@SystemApi
+@TestApi
public class HwParcel {
private static final String TAG = "HwParcel";
diff --git a/core/java/android/os/IHwBinder.java b/core/java/android/os/IHwBinder.java
index 249eb3aa3456..46fa6ef3b783 100644
--- a/core/java/android/os/IHwBinder.java
+++ b/core/java/android/os/IHwBinder.java
@@ -17,9 +17,11 @@
package android.os;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
/** @hide */
@SystemApi
+@TestApi
public interface IHwBinder {
/**
* Process a hwbinder transaction.
diff --git a/core/java/android/os/IHwInterface.java b/core/java/android/os/IHwInterface.java
index f9edd5bf8883..0a5a71550b06 100644
--- a/core/java/android/os/IHwInterface.java
+++ b/core/java/android/os/IHwInterface.java
@@ -17,8 +17,11 @@
package android.os;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
/** @hide */
@SystemApi
+@TestApi
public interface IHwInterface {
/**
* @return the binder object that corresponds to this interface.
diff --git a/core/java/android/os/NativeHandle.java b/core/java/android/os/NativeHandle.java
index f7ffc37f085f..f13bf5fccd38 100644
--- a/core/java/android/os/NativeHandle.java
+++ b/core/java/android/os/NativeHandle.java
@@ -20,6 +20,7 @@ import static android.system.OsConstants.F_DUPFD_CLOEXEC;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.system.ErrnoException;
import android.system.Os;
@@ -32,6 +33,7 @@ import java.io.FileDescriptor;
* @hide
*/
@SystemApi
+@TestApi
public final class NativeHandle implements Closeable {
// whether this object owns mFds
private boolean mOwn = false;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index ee56e3d0ad16..760fef7566c7 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -208,30 +208,35 @@ public class Process {
* First uid used for fully isolated sandboxed processes spawned from an app zygote
* @hide
*/
+ @TestApi
public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;
/**
* Number of UIDs we allocate per application zygote
* @hide
*/
+ @TestApi
public static final int NUM_UIDS_PER_APP_ZYGOTE = 100;
/**
* Last uid used for fully isolated sandboxed processes spawned from an app zygote
* @hide
*/
+ @TestApi
public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;
/**
* First uid used for fully isolated sandboxed processes (with no permissions of their own)
* @hide
*/
+ @TestApi
public static final int FIRST_ISOLATED_UID = 99000;
/**
* Last uid used for fully isolated sandboxed processes (with no permissions of their own)
* @hide
*/
+ @TestApi
public static final int LAST_ISOLATED_UID = 99999;
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ef117eaaecc6..64aa062a3c49 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8681,10 +8681,10 @@ public final class Settings {
CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
- CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
+ CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index eef7ea232d43..50e7ec30ec3a 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -37,7 +37,6 @@ import android.widget.TextView;
import com.android.i18n.phonenumbers.PhoneNumberMatch;
import com.android.i18n.phonenumbers.PhoneNumberUtil;
import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
-import com.android.internal.annotations.GuardedBy;
import libcore.util.EmptyArray;
@@ -49,6 +48,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
+import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -69,7 +69,6 @@ import java.util.regex.Pattern;
*
* @see MatchFilter
* @see TransformFilter
- * @see UrlSpanFactory
*/
public class Linkify {
@@ -228,44 +227,6 @@ public class Linkify {
}
/**
- * Factory class to create {@link URLSpan}s. While adding spans to a {@link Spannable},
- * {@link Linkify} will call {@link UrlSpanFactory#create(String)} function to create a
- * {@link URLSpan}.
- *
- * @see #addLinks(Spannable, int, UrlSpanFactory)
- * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
- * UrlSpanFactory)
- */
- public static class UrlSpanFactory {
- private static final Object sInstanceLock = new Object();
-
- @GuardedBy("sInstanceLock")
- private static volatile UrlSpanFactory sInstance = null;
-
- private static synchronized UrlSpanFactory getInstance() {
- if (sInstance == null) {
- synchronized (sInstanceLock) {
- if (sInstance == null) {
- sInstance = new UrlSpanFactory();
- }
- }
- }
- return sInstance;
- }
-
- /**
- * Factory function that will called by {@link Linkify} in order to create a
- * {@link URLSpan}.
- *
- * @param url URL found
- * @return a URLSpan instance
- */
- public URLSpan create(final String url) {
- return new URLSpan(url);
- }
- }
-
- /**
* Scans the text of the provided Spannable and turns all occurrences
* of the link types indicated in the mask into clickable links.
* If the mask is nonzero, it also removes any existing URLSpans
@@ -277,7 +238,7 @@ public class Linkify {
*
* @return True if at least one link is found and applied.
*
- * @see #addLinks(Spannable, int, UrlSpanFactory)
+ * @see #addLinks(Spannable, int, Function)
*/
public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
return addLinks(text, mask, null, null);
@@ -292,11 +253,11 @@ public class Linkify {
*
* @param text Spannable whose text is to be marked-up with links
* @param mask mask to define which kinds of links will be searched
- * @param urlSpanFactory factory class used to create {@link URLSpan}s
+ * @param urlSpanFactory function used to create {@link URLSpan}s
* @return True if at least one link is found and applied.
*/
public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
- @Nullable UrlSpanFactory urlSpanFactory) {
+ @Nullable Function<String, URLSpan> urlSpanFactory) {
return addLinks(text, mask, null, urlSpanFactory);
}
@@ -309,11 +270,11 @@ public class Linkify {
* @param text Spannable whose text is to be marked-up with links
* @param mask mask to define which kinds of links will be searched
* @param context Context to be used while identifying phone numbers
- * @param urlSpanFactory factory class used to create {@link URLSpan}s
+ * @param urlSpanFactory function used to create {@link URLSpan}s
* @return true if at least one link is found and applied.
*/
private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask,
- @Nullable Context context, @Nullable UrlSpanFactory urlSpanFactory) {
+ @Nullable Context context, @Nullable Function<String, URLSpan> urlSpanFactory) {
if (text != null && containsUnsupportedCharacters(text.toString())) {
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
return false;
@@ -398,7 +359,7 @@ public class Linkify {
*
* @return True if at least one link is found and applied.
*
- * @see #addLinks(Spannable, int, UrlSpanFactory)
+ * @see #addLinks(Spannable, int, Function)
*/
public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
if (mask == 0) {
@@ -512,8 +473,7 @@ public class Linkify {
* @param pattern Regex pattern to be used for finding links
* @param scheme URL scheme string (eg <code>http://</code>) to be
* prepended to the links that do not start with this scheme.
- * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
- * UrlSpanFactory)
+ * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
*/
public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
@Nullable String scheme) {
@@ -534,8 +494,7 @@ public class Linkify {
* @param transformFilter Filter to allow the client code to update the link found.
*
* @return True if at least one link is found and applied.
- * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
- * UrlSpanFactory)
+ * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
*/
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
@Nullable String scheme, @Nullable MatchFilter matchFilter,
@@ -560,8 +519,7 @@ public class Linkify {
*
* @return True if at least one link is found and applied.
*
- * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter,
- * UrlSpanFactory)
+ * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function)
*/
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
@Nullable String defaultScheme, @Nullable String[] schemes,
@@ -584,14 +542,14 @@ public class Linkify {
* @param matchFilter the filter that is used to allow the client code additional control
* over which pattern matches are to be converted into links.
* @param transformFilter filter to allow the client code to update the link found.
- * @param urlSpanFactory factory class used to create {@link URLSpan}s
+ * @param urlSpanFactory function used to create {@link URLSpan}s
*
* @return True if at least one link is found and applied.
*/
public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
@Nullable String defaultScheme, @Nullable String[] schemes,
@Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter,
- @Nullable UrlSpanFactory urlSpanFactory) {
+ @Nullable Function<String, URLSpan> urlSpanFactory) {
if (spannable != null && containsUnsupportedCharacters(spannable.toString())) {
android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, "");
return false;
@@ -634,11 +592,11 @@ public class Linkify {
}
private static void applyLink(String url, int start, int end, Spannable text,
- @Nullable UrlSpanFactory urlSpanFactory) {
+ @Nullable Function<String, URLSpan> urlSpanFactory) {
if (urlSpanFactory == null) {
- urlSpanFactory = UrlSpanFactory.getInstance();
+ urlSpanFactory = DEFAULT_SPAN_FACTORY;
}
- final URLSpan span = urlSpanFactory.create(url);
+ final URLSpan span = urlSpanFactory.apply(url);
text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
@@ -805,6 +763,13 @@ public class Linkify {
i++;
}
}
+
+ /**
+ * Default factory function to create {@link URLSpan}s. While adding spans to a
+ * {@link Spannable}, {@link Linkify} will call this function to create a {@link URLSpan}.
+ */
+ private static final Function<String, URLSpan> DEFAULT_SPAN_FACTORY =
+ (String string) -> new URLSpan(string);
}
class LinkSpec {
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
new file mode 100644
index 000000000000..1a6e5d8e8b03
--- /dev/null
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2018 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.textclassifier;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.RemoteAction;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+
+/** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
+public final class ConversationAction implements Parcelable {
+
+ /** @hide */
+ @Retention(SOURCE)
+ @StringDef(
+ value = {
+ TYPE_VIEW_CALENDAR,
+ TYPE_VIEW_MAP,
+ TYPE_TRACK_FLIGHT,
+ TYPE_OPEN_URL,
+ TYPE_SEND_SMS,
+ TYPE_CALL_PHONE,
+ TYPE_SEND_EMAIL,
+ TYPE_TEXT_REPLY,
+ TYPE_CREATE_REMINDER,
+ TYPE_SHARE_LOCATION
+ },
+ prefix = "TYPE_")
+ public @interface ActionType {}
+
+ /**
+ * Indicates an action to view a calendar at a specified time.
+ */
+ public static final String TYPE_VIEW_CALENDAR = "view_calendar";
+ /**
+ * Indicates an action to view the map at a specified location.
+ */
+ public static final String TYPE_VIEW_MAP = "view_map";
+ /**
+ * Indicates an action to track a flight.
+ */
+ public static final String TYPE_TRACK_FLIGHT = "track_flight";
+ /**
+ * Indicates an action to open an URL.
+ */
+ public static final String TYPE_OPEN_URL = "open_url";
+ /**
+ * Indicates an action to send a SMS.
+ */
+ public static final String TYPE_SEND_SMS = "send_sms";
+ /**
+ * Indicates an action to call a phone number.
+ */
+ public static final String TYPE_CALL_PHONE = "call_phone";
+ /**
+ * Indicates an action to send an email.
+ */
+ public static final String TYPE_SEND_EMAIL = "send_email";
+ /**
+ * Indicates an action to reply with a text message.
+ */
+ public static final String TYPE_TEXT_REPLY = "text_reply";
+ /**
+ * Indicates an action to create a reminder.
+ */
+ public static final String TYPE_CREATE_REMINDER = "create_reminder";
+ /**
+ * Indicates an action to reply with a location.
+ */
+ public static final String TYPE_SHARE_LOCATION = "share_location";
+
+ public static final Creator<ConversationAction> CREATOR =
+ new Creator<ConversationAction>() {
+ @Override
+ public ConversationAction createFromParcel(Parcel in) {
+ return new ConversationAction(in);
+ }
+
+ @Override
+ public ConversationAction[] newArray(int size) {
+ return new ConversationAction[size];
+ }
+ };
+
+ @NonNull
+ @ActionType
+ private final String mType;
+ @NonNull
+ private final CharSequence mTextReply;
+ @Nullable
+ private final RemoteAction mAction;
+
+ @FloatRange(from = 0, to = 1)
+ private final float mScore;
+
+ @NonNull
+ private final Bundle mExtras;
+
+ private ConversationAction(
+ @NonNull String type,
+ @Nullable RemoteAction action,
+ @Nullable CharSequence textReply,
+ float score,
+ @NonNull Bundle extras) {
+ mType = Preconditions.checkNotNull(type);
+ mAction = action;
+ mTextReply = textReply;
+ mScore = score;
+ mExtras = Preconditions.checkNotNull(extras);
+ }
+
+ private ConversationAction(Parcel in) {
+ mType = in.readString();
+ mAction = in.readParcelable(null);
+ mTextReply = in.readCharSequence();
+ mScore = in.readFloat();
+ mExtras = in.readBundle();
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mType);
+ parcel.writeParcelable(mAction, flags);
+ parcel.writeCharSequence(mTextReply);
+ parcel.writeFloat(mScore);
+ parcel.writeBundle(mExtras);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
+ @NonNull
+ @ActionType
+ public String getType() {
+ return mType;
+ }
+
+ /**
+ * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
+ * the specified action type.
+ */
+ @Nullable
+ public RemoteAction getAction() {
+ return mAction;
+ }
+
+ /**
+ * Returns the confidence score for the specified action. The value ranges from 0 (low
+ * confidence) to 1 (high confidence).
+ */
+ @FloatRange(from = 0, to = 1)
+ public float getConfidenceScore() {
+ return mScore;
+ }
+
+ /**
+ * Returns the text reply that could be sent as a reply to the given conversation.
+ * <p>
+ * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
+ */
+ @Nullable
+ public CharSequence getTextReply() {
+ return mTextReply;
+ }
+
+ /**
+ * Returns the extended data related to this conversation action.
+ *
+ * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
+ * prefer to hold a reference to the returned bundle rather than frequently calling this
+ * method.
+ */
+ @NonNull
+ public Bundle getExtras() {
+ return mExtras.deepCopy();
+ }
+
+ /** Builder class to construct {@link ConversationAction}. */
+ public static final class Builder {
+ @Nullable
+ @ActionType
+ private String mType;
+ @Nullable
+ private RemoteAction mAction;
+ @Nullable
+ private CharSequence mTextReply;
+ private float mScore;
+ @Nullable
+ private Bundle mExtras;
+
+ public Builder(@NonNull @ActionType String actionType) {
+ mType = Preconditions.checkNotNull(actionType);
+ }
+
+ /**
+ * Sets an action that may be performed on the given conversation.
+ */
+ @NonNull
+ public Builder setAction(@Nullable RemoteAction action) {
+ mAction = action;
+ return this;
+ }
+
+ /**
+ * Sets a text reply that may be performed on the given conversation.
+ */
+ @NonNull
+ public Builder setTextReply(@Nullable CharSequence textReply) {
+ mTextReply = textReply;
+ return this;
+ }
+
+ /** Sets the confident score. */
+ @NonNull
+ public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
+ mScore = score;
+ return this;
+ }
+
+ /**
+ * Sets the extended data for the conversation action object.
+ */
+ @NonNull
+ public Builder setExtras(@Nullable Bundle extras) {
+ mExtras = extras;
+ return this;
+ }
+
+ /** Builds the {@link ConversationAction} object. */
+ @NonNull
+ public ConversationAction build() {
+ return new ConversationAction(
+ mType,
+ mAction,
+ mTextReply,
+ mScore,
+ mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
+ }
+ }
+}
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 3f690f70d275..f7c1a2640dc5 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -17,18 +17,15 @@ package android.view.textclassifier;
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.app.Person;
-import android.app.RemoteAction;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.SpannedString;
-import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -37,10 +34,8 @@ import java.lang.annotation.Retention;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
/**
* Represents a list of actions suggested by a {@link TextClassifier} on a given conversation.
@@ -62,83 +57,6 @@ public final class ConversationActions implements Parcelable {
}
};
- /** @hide */
- @Retention(SOURCE)
- @StringDef(
- value = {
- TYPE_VIEW_CALENDAR,
- TYPE_VIEW_MAP,
- TYPE_TRACK_FLIGHT,
- TYPE_OPEN_URL,
- TYPE_SEND_SMS,
- TYPE_CALL_PHONE,
- TYPE_SEND_EMAIL,
- TYPE_TEXT_REPLY,
- TYPE_CREATE_REMINDER,
- TYPE_SHARE_LOCATION
- },
- prefix = "TYPE_")
- public @interface ActionType {}
-
- /**
- * Indicates an action to view a calendar at a specified time.
- */
- public static final String TYPE_VIEW_CALENDAR = "view_calendar";
- /**
- * Indicates an action to view the map at a specified location.
- */
- public static final String TYPE_VIEW_MAP = "view_map";
- /**
- * Indicates an action to track a flight.
- */
- public static final String TYPE_TRACK_FLIGHT = "track_flight";
- /**
- * Indicates an action to open an URL.
- */
- public static final String TYPE_OPEN_URL = "open_url";
- /**
- * Indicates an action to send a SMS.
- */
- public static final String TYPE_SEND_SMS = "send_sms";
- /**
- * Indicates an action to call a phone number.
- */
- public static final String TYPE_CALL_PHONE = "call_phone";
- /**
- * Indicates an action to send an email.
- */
- public static final String TYPE_SEND_EMAIL = "send_email";
- /**
- * Indicates an action to reply with a text message.
- */
- public static final String TYPE_TEXT_REPLY = "text_reply";
- /**
- * Indicates an action to create a reminder.
- */
- public static final String TYPE_CREATE_REMINDER = "create_reminder";
- /**
- * Indicates an action to reply with a location.
- */
- public static final String TYPE_SHARE_LOCATION = "share_location";
-
- /** @hide */
- @Retention(SOURCE)
- @StringDef(
- value = {
- HINT_FOR_NOTIFICATION,
- HINT_FOR_IN_APP,
- },
- prefix = "HINT_")
- public @interface Hint {}
- /**
- * To indicate the generated actions will be used within the app.
- */
- public static final String HINT_FOR_IN_APP = "in_app";
- /**
- * To indicate the generated actions will be used for notification.
- */
- public static final String HINT_FOR_NOTIFICATION = "notification";
-
private final List<ConversationAction> mConversationActions;
private final String mId;
@@ -184,182 +102,6 @@ public final class ConversationActions implements Parcelable {
return mId;
}
- /** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
- public static final class ConversationAction implements Parcelable {
-
- public static final Creator<ConversationAction> CREATOR =
- new Creator<ConversationAction>() {
- @Override
- public ConversationAction createFromParcel(Parcel in) {
- return new ConversationAction(in);
- }
-
- @Override
- public ConversationAction[] newArray(int size) {
- return new ConversationAction[size];
- }
- };
-
- @NonNull
- @ActionType
- private final String mType;
- @NonNull
- private final CharSequence mTextReply;
- @Nullable
- private final RemoteAction mAction;
-
- @FloatRange(from = 0, to = 1)
- private final float mScore;
-
- @NonNull
- private final Bundle mExtras;
-
- private ConversationAction(
- @NonNull String type,
- @Nullable RemoteAction action,
- @Nullable CharSequence textReply,
- float score,
- @NonNull Bundle extras) {
- mType = Preconditions.checkNotNull(type);
- mAction = action;
- mTextReply = textReply;
- mScore = score;
- mExtras = Preconditions.checkNotNull(extras);
- }
-
- private ConversationAction(Parcel in) {
- mType = in.readString();
- mAction = in.readParcelable(null);
- mTextReply = in.readCharSequence();
- mScore = in.readFloat();
- mExtras = in.readBundle();
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeString(mType);
- parcel.writeParcelable(mAction, flags);
- parcel.writeCharSequence(mTextReply);
- parcel.writeFloat(mScore);
- parcel.writeBundle(mExtras);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @NonNull
- @ActionType
- /** Returns the type of this action, for example, {@link #TYPE_VIEW_CALENDAR}. */
- public String getType() {
- return mType;
- }
-
- @Nullable
- /**
- * Returns a RemoteAction object, which contains the icon, label and a PendingIntent, for
- * the specified action type.
- */
- public RemoteAction getAction() {
- return mAction;
- }
-
- /**
- * Returns the confidence score for the specified action. The value ranges from 0 (low
- * confidence) to 1 (high confidence).
- */
- @FloatRange(from = 0, to = 1)
- public float getConfidenceScore() {
- return mScore;
- }
-
- /**
- * Returns the text reply that could be sent as a reply to the given conversation.
- * <p>
- * This is only available when the type of the action is {@link #TYPE_TEXT_REPLY}.
- */
- @Nullable
- public CharSequence getTextReply() {
- return mTextReply;
- }
-
- /**
- * Returns the extended data related to this conversation action.
- *
- * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
- * prefer to hold a reference to the returned bundle rather than frequently calling this
- * method.
- */
- @NonNull
- public Bundle getExtras() {
- return mExtras.deepCopy();
- }
-
- /** Builder class to construct {@link ConversationAction}. */
- public static final class Builder {
- @Nullable
- @ActionType
- private String mType;
- @Nullable
- private RemoteAction mAction;
- @Nullable
- private CharSequence mTextReply;
- private float mScore;
- @Nullable
- private Bundle mExtras;
-
- public Builder(@NonNull @ActionType String actionType) {
- mType = Preconditions.checkNotNull(actionType);
- }
-
- /**
- * Sets an action that may be performed on the given conversation.
- */
- @NonNull
- public Builder setAction(@Nullable RemoteAction action) {
- mAction = action;
- return this;
- }
-
- /**
- * Sets a text reply that may be performed on the given conversation.
- */
- @NonNull
- public Builder setTextReply(@Nullable CharSequence textReply) {
- mTextReply = textReply;
- return this;
- }
-
- /** Sets the confident score. */
- @NonNull
- public Builder setConfidenceScore(@FloatRange(from = 0, to = 1) float score) {
- mScore = score;
- return this;
- }
-
- /**
- * Sets the extended data for the conversation action object.
- */
- @NonNull
- public Builder setExtras(@Nullable Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /** Builds the {@link ConversationAction} object. */
- @NonNull
- public ConversationAction build() {
- return new ConversationAction(
- mType,
- mAction,
- mTextReply,
- mScore,
- mExtras == null ? Bundle.EMPTY : mExtras.deepCopy());
- }
- }
- }
-
/** Represents a message in the conversation. */
public static final class Message implements Parcelable {
/**
@@ -538,156 +280,36 @@ public final class ConversationActions implements Parcelable {
}
}
- /** Configuration object for specifying what action types to identify. */
- public static final class TypeConfig implements Parcelable {
- @NonNull
- @ActionType
- private final Set<String> mExcludedTypes;
- @NonNull
- @ActionType
- private final Set<String> mIncludedTypes;
- private final boolean mIncludeTypesFromTextClassifier;
-
- private TypeConfig(
- @NonNull Set<String> includedTypes,
- @NonNull Set<String> excludedTypes,
- boolean includeTypesFromTextClassifier) {
- mIncludedTypes = Preconditions.checkNotNull(includedTypes);
- mExcludedTypes = Preconditions.checkNotNull(excludedTypes);
- mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
- }
-
- private TypeConfig(Parcel in) {
- mIncludedTypes = new ArraySet<>(in.createStringArrayList());
- mExcludedTypes = new ArraySet<>(in.createStringArrayList());
- mIncludeTypesFromTextClassifier = in.readByte() != 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int flags) {
- parcel.writeStringList(new ArrayList<>(mIncludedTypes));
- parcel.writeStringList(new ArrayList<>(mExcludedTypes));
- parcel.writeByte((byte) (mIncludeTypesFromTextClassifier ? 1 : 0));
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Creator<TypeConfig> CREATOR =
- new Creator<TypeConfig>() {
- @Override
- public TypeConfig createFromParcel(Parcel in) {
- return new TypeConfig(in);
- }
+ /**
+ * A request object for generating conversation action suggestions.
+ *
+ * @see TextClassifier#suggestConversationActions(Request)
+ */
+ public static final class Request implements Parcelable {
- @Override
- public TypeConfig[] newArray(int size) {
- return new TypeConfig[size];
- }
- };
+ /** @hide */
+ @Retention(SOURCE)
+ @StringDef(
+ value = {
+ HINT_FOR_NOTIFICATION,
+ HINT_FOR_IN_APP,
+ },
+ prefix = "HINT_")
+ public @interface Hint {}
/**
- * Returns a final list of types that the text classifier should look for.
- *
- * <p>NOTE: This method is intended for use by a text classifier.
- *
- * @param defaultTypes types the text classifier thinks should be included before factoring
- * in the included/excluded types given by the client.
+ * To indicate the generated actions will be used within the app.
*/
- @NonNull
- public Collection<String> resolveTypes(@Nullable Collection<String> defaultTypes) {
- Set<String> types = new ArraySet<>();
- if (mIncludeTypesFromTextClassifier && defaultTypes != null) {
- types.addAll(defaultTypes);
- }
- types.addAll(mIncludedTypes);
- types.removeAll(mExcludedTypes);
- return Collections.unmodifiableCollection(types);
- }
-
+ public static final String HINT_FOR_IN_APP = "in_app";
/**
- * Return whether the client allows the text classifier to include its own list of default
- * types. If this function returns {@code true}, the text classifier can consider specifying
- * a default list of entity types in {@link #resolveTypes(Collection)}.
- *
- * <p>NOTE: This method is intended for use by a text classifier.
- *
- * @see #resolveTypes(Collection)
+ * To indicate the generated actions will be used for notification.
*/
- public boolean shouldIncludeTypesFromTextClassifier() {
- return mIncludeTypesFromTextClassifier;
- }
-
- /** Builder class to construct the {@link TypeConfig} object. */
- public static final class Builder {
- @Nullable
- private Collection<String> mExcludedTypes;
- @Nullable
- private Collection<String> mIncludedTypes;
- private boolean mIncludeTypesFromTextClassifier = true;
-
- /**
- * Sets a collection of types that are explicitly included, for example, {@link
- * #TYPE_VIEW_CALENDAR}.
- */
- @NonNull
- public Builder setIncludedTypes(
- @Nullable @ActionType Collection<String> includedTypes) {
- mIncludedTypes = includedTypes;
- return this;
- }
-
- /**
- * Sets a collection of types that are explicitly excluded, for example, {@link
- * #TYPE_VIEW_CALENDAR}.
- */
- @NonNull
- public Builder setExcludedTypes(
- @Nullable @ActionType Collection<String> excludedTypes) {
- mExcludedTypes = excludedTypes;
- return this;
- }
-
- /**
- * Specifies whether or not to include the types suggested by the text classifier. By
- * default, it is included.
- */
- @NonNull
- public Builder includeTypesFromTextClassifier(boolean includeTypesFromTextClassifier) {
- mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
- return this;
- }
-
- /**
- * Combines all of the options that have been set and returns a new {@link TypeConfig}
- * object.
- */
- @NonNull
- public TypeConfig build() {
- return new TypeConfig(
- mIncludedTypes == null
- ? Collections.emptySet()
- : new ArraySet<>(mIncludedTypes),
- mExcludedTypes == null
- ? Collections.emptySet()
- : new ArraySet<>(mExcludedTypes),
- mIncludeTypesFromTextClassifier);
- }
- }
- }
+ public static final String HINT_FOR_NOTIFICATION = "notification";
- /**
- * A request object for generating conversation action suggestions.
- *
- * @see TextClassifier#suggestConversationActions(Request)
- */
- public static final class Request implements Parcelable {
@NonNull
private final List<Message> mConversation;
@NonNull
- private final TypeConfig mTypeConfig;
+ private final TextClassifier.EntityConfig mTypeConfig;
private final int mMaxSuggestions;
@NonNull
@Hint
@@ -699,7 +321,7 @@ public final class ConversationActions implements Parcelable {
private Request(
@NonNull List<Message> conversation,
- @NonNull TypeConfig typeConfig,
+ @NonNull TextClassifier.EntityConfig typeConfig,
int maxSuggestions,
String conversationId,
@Nullable @Hint List<String> hints) {
@@ -713,7 +335,7 @@ public final class ConversationActions implements Parcelable {
private static Request readFromParcel(Parcel in) {
List<Message> conversation = new ArrayList<>();
in.readParcelableList(conversation, null);
- TypeConfig typeConfig = in.readParcelable(null);
+ TextClassifier.EntityConfig typeConfig = in.readParcelable(null);
int maxSuggestions = in.readInt();
String conversationId = in.readString();
List<String> hints = new ArrayList<>();
@@ -760,7 +382,7 @@ public final class ConversationActions implements Parcelable {
/** Returns the type config. */
@NonNull
- public TypeConfig getTypeConfig() {
+ public TextClassifier.EntityConfig getTypeConfig() {
return mTypeConfig;
}
@@ -820,7 +442,7 @@ public final class ConversationActions implements Parcelable {
@NonNull
private List<Message> mConversation;
@Nullable
- private TypeConfig mTypeConfig;
+ private TextClassifier.EntityConfig mTypeConfig;
private int mMaxSuggestions;
@Nullable
private String mConversationId;
@@ -849,7 +471,7 @@ public final class ConversationActions implements Parcelable {
/** Sets the type config. */
@NonNull
- public Builder setTypeConfig(@Nullable TypeConfig typeConfig) {
+ public Builder setTypeConfig(@Nullable TextClassifier.EntityConfig typeConfig) {
mTypeConfig = typeConfig;
return this;
}
@@ -879,7 +501,9 @@ public final class ConversationActions implements Parcelable {
public Request build() {
return new Request(
Collections.unmodifiableList(mConversation),
- mTypeConfig == null ? new TypeConfig.Builder().build() : mTypeConfig,
+ mTypeConfig == null
+ ? new TextClassifier.EntityConfig.Builder().build()
+ : mTypeConfig,
mMaxSuggestions,
mConversationId,
mHints == null
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 50801a2b3e3f..ce680ecbd119 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -117,15 +117,15 @@ public final class TextClassificationConstants {
.add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES =
new StringJoiner(ENTITY_LIST_DELIMITER)
- .add(ConversationActions.TYPE_TEXT_REPLY)
- .add(ConversationActions.TYPE_CREATE_REMINDER)
- .add(ConversationActions.TYPE_CALL_PHONE)
- .add(ConversationActions.TYPE_OPEN_URL)
- .add(ConversationActions.TYPE_SEND_EMAIL)
- .add(ConversationActions.TYPE_SEND_SMS)
- .add(ConversationActions.TYPE_TRACK_FLIGHT)
- .add(ConversationActions.TYPE_VIEW_CALENDAR)
- .add(ConversationActions.TYPE_VIEW_MAP)
+ .add(ConversationAction.TYPE_TEXT_REPLY)
+ .add(ConversationAction.TYPE_CREATE_REMINDER)
+ .add(ConversationAction.TYPE_CALL_PHONE)
+ .add(ConversationAction.TYPE_OPEN_URL)
+ .add(ConversationAction.TYPE_SEND_EMAIL)
+ .add(ConversationAction.TYPE_SEND_SMS)
+ .add(ConversationAction.TYPE_TRACK_FLIGHT)
+ .add(ConversationAction.TYPE_VIEW_CALENDAR)
+ .add(ConversationAction.TYPE_VIEW_MAP)
.toString();
private final boolean mSystemTextClassifierEnabled;
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 8709e09bbf55..5a5613605e36 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -32,7 +32,6 @@ import android.text.style.URLSpan;
import android.text.util.Linkify;
import android.text.util.Linkify.LinkifyMask;
import android.util.ArrayMap;
-import android.util.ArraySet;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -43,6 +42,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -324,7 +324,7 @@ public interface TextClassifier {
}
/**
- * Detects the language of the specified text.
+ * Detects the language of the text in the given request.
*
* <p><strong>NOTE: </strong>Call on a worker thread.
*
@@ -403,42 +403,59 @@ public interface TextClassifier {
default void dump(@NonNull IndentingPrintWriter printWriter) {}
/**
- * Configuration object for specifying what entities to identify.
+ * Configuration object for specifying what entity types to identify.
*
* Configs are initially based on a predefined preset, and can be modified from there.
*/
final class EntityConfig implements Parcelable {
- private final Collection<String> mHints;
- private final Collection<String> mExcludedEntityTypes;
- private final Collection<String> mIncludedEntityTypes;
- private final boolean mUseHints;
-
- private EntityConfig(boolean useHints, Collection<String> hints,
- Collection<String> includedEntityTypes, Collection<String> excludedEntityTypes) {
- mHints = hints == null
- ? Collections.EMPTY_LIST
- : Collections.unmodifiableCollection(new ArraySet<>(hints));
- mExcludedEntityTypes = excludedEntityTypes == null
- ? Collections.EMPTY_LIST : new ArraySet<>(excludedEntityTypes);
- mIncludedEntityTypes = includedEntityTypes == null
- ? Collections.EMPTY_LIST : new ArraySet<>(includedEntityTypes);
- mUseHints = useHints;
+ private final List<String> mIncludedTypes;
+ private final List<String> mExcludedTypes;
+ private final List<String> mHints;
+ private final boolean mIncludeTypesFromTextClassifier;
+
+ private EntityConfig(
+ List<String> includedEntityTypes,
+ List<String> excludedEntityTypes,
+ List<String> hints,
+ boolean includeTypesFromTextClassifier) {
+ mIncludedTypes = Preconditions.checkNotNull(includedEntityTypes);
+ mExcludedTypes = Preconditions.checkNotNull(excludedEntityTypes);
+ mHints = Preconditions.checkNotNull(hints);
+ mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
+ }
+
+ private EntityConfig(Parcel in) {
+ mIncludedTypes = new ArrayList<>();
+ in.readStringList(mIncludedTypes);
+ mExcludedTypes = new ArrayList<>();
+ in.readStringList(mExcludedTypes);
+ List<String> tmpHints = new ArrayList<>();
+ in.readStringList(tmpHints);
+ mHints = Collections.unmodifiableList(tmpHints);
+ mIncludeTypesFromTextClassifier = in.readByte() != 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeStringList(mIncludedTypes);
+ parcel.writeStringList(mExcludedTypes);
+ parcel.writeStringList(mHints);
+ parcel.writeByte((byte) (mIncludeTypesFromTextClassifier ? 1 : 0));
}
/**
* Creates an EntityConfig.
*
* @param hints Hints for the TextClassifier to determine what types of entities to find.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public static EntityConfig createWithHints(@Nullable Collection<String> hints) {
- return new EntityConfig(/* useHints */ true, hints,
- /* includedEntityTypes */null, /* excludedEntityTypes */ null);
- }
-
- // TODO: Remove once apps can build against the latest sdk.
- /** @hide */
- public static EntityConfig create(@Nullable Collection<String> hints) {
- return createWithHints(hints);
+ return new EntityConfig.Builder()
+ .includeTypesFromTextClassifier(true)
+ .setHints(hints)
+ .build();
}
/**
@@ -450,12 +467,19 @@ public interface TextClassifier {
*
*
* Note that if an entity has been excluded, the exclusion will take precedence.
+ *
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public static EntityConfig create(@Nullable Collection<String> hints,
@Nullable Collection<String> includedEntityTypes,
@Nullable Collection<String> excludedEntityTypes) {
- return new EntityConfig(/* useHints */ true, hints,
- includedEntityTypes, excludedEntityTypes);
+ return new EntityConfig.Builder()
+ .setIncludedTypes(includedEntityTypes)
+ .setExcludedTypes(excludedEntityTypes)
+ .setHints(hints)
+ .includeTypesFromTextClassifier(true)
+ .build();
}
/**
@@ -463,34 +487,33 @@ public interface TextClassifier {
*
* @param entityTypes Complete set of entities, e.g. {@link #TYPE_URL} to find.
*
+ * @deprecated Use {@link Builder} instead.
*/
+ @Deprecated
public static EntityConfig createWithExplicitEntityList(
@Nullable Collection<String> entityTypes) {
- return new EntityConfig(/* useHints */ false, /* hints */ null,
- /* includedEntityTypes */ entityTypes, /* excludedEntityTypes */ null);
- }
-
- // TODO: Remove once apps can build against the latest sdk.
- /** @hide */
- public static EntityConfig createWithEntityList(@Nullable Collection<String> entityTypes) {
- return createWithExplicitEntityList(entityTypes);
+ return new EntityConfig.Builder()
+ .setIncludedTypes(entityTypes)
+ .includeTypesFromTextClassifier(false)
+ .build();
}
/**
- * Returns a list of the final set of entities to find.
+ * Returns a final list of entity types to find.
*
- * @param entities Entities we think should be found before factoring in includes/excludes
+ * @param entityTypes Entity types we think should be found before factoring in
+ * includes/excludes
*
* This method is intended for use by TextClassifier implementations.
*/
public Collection<String> resolveEntityListModifications(
- @NonNull Collection<String> entities) {
- final Set<String> finalSet = new HashSet();
- if (mUseHints) {
- finalSet.addAll(entities);
+ @NonNull Collection<String> entityTypes) {
+ final Set<String> finalSet = new HashSet<>();
+ if (mIncludeTypesFromTextClassifier) {
+ finalSet.addAll(entityTypes);
}
- finalSet.addAll(mIncludedEntityTypes);
- finalSet.removeAll(mExcludedEntityTypes);
+ finalSet.addAll(mIncludedTypes);
+ finalSet.removeAll(mExcludedTypes);
return finalSet;
}
@@ -503,17 +526,22 @@ public interface TextClassifier {
return mHints;
}
- @Override
- public int describeContents() {
- return 0;
+ /**
+ * Return whether the client allows the text classifier to include its own list of
+ * default types. If this function returns {@code true}, a default list of types suggested
+ * from a text classifier will be taking into account.
+ *
+ * <p>NOTE: This method is intended for use by a text classifier.
+ *
+ * @see #resolveEntityListModifications(Collection)
+ */
+ public boolean shouldIncludeTypesFromTextClassifier() {
+ return mIncludeTypesFromTextClassifier;
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStringList(new ArrayList<>(mHints));
- dest.writeStringList(new ArrayList<>(mExcludedEntityTypes));
- dest.writeStringList(new ArrayList<>(mIncludedEntityTypes));
- dest.writeInt(mUseHints ? 1 : 0);
+ public int describeContents() {
+ return 0;
}
public static final Parcelable.Creator<EntityConfig> CREATOR =
@@ -529,11 +557,75 @@ public interface TextClassifier {
}
};
- private EntityConfig(Parcel in) {
- mHints = new ArraySet<>(in.createStringArrayList());
- mExcludedEntityTypes = new ArraySet<>(in.createStringArrayList());
- mIncludedEntityTypes = new ArraySet<>(in.createStringArrayList());
- mUseHints = in.readInt() == 1;
+
+
+ /** Builder class to construct the {@link EntityConfig} object. */
+ public static final class Builder {
+ @Nullable
+ private Collection<String> mIncludedTypes;
+ @Nullable
+ private Collection<String> mExcludedTypes;
+ @Nullable
+ private Collection<String> mHints;
+ private boolean mIncludeTypesFromTextClassifier = true;
+
+ /**
+ * Sets a collection of types that are explicitly included.
+ */
+ @NonNull
+ public Builder setIncludedTypes(@Nullable Collection<String> includedTypes) {
+ mIncludedTypes = includedTypes;
+ return this;
+ }
+
+ /**
+ * Sets a collection of types that are explicitly excluded.
+ */
+ @NonNull
+ public Builder setExcludedTypes(@Nullable Collection<String> excludedTypes) {
+ mExcludedTypes = excludedTypes;
+ return this;
+ }
+
+ /**
+ * Specifies whether or not to include the types suggested by the text classifier. By
+ * default, it is included.
+ */
+ @NonNull
+ public Builder includeTypesFromTextClassifier(boolean includeTypesFromTextClassifier) {
+ mIncludeTypesFromTextClassifier = includeTypesFromTextClassifier;
+ return this;
+ }
+
+
+ /**
+ * Sets the hints for the TextClassifier to determine what types of entities to find.
+ * These hints will only be used if {@link #includeTypesFromTextClassifier} is
+ * set to be true.
+ */
+ public Builder setHints(Collection<String> hints) {
+ mHints = hints;
+ return this;
+ }
+
+ /**
+ * Combines all of the options that have been set and returns a new {@link EntityConfig}
+ * object.
+ */
+ @NonNull
+ public EntityConfig build() {
+ return new EntityConfig(
+ mIncludedTypes == null
+ ? Collections.emptyList()
+ : new ArrayList<>(mIncludedTypes),
+ mExcludedTypes == null
+ ? Collections.emptyList()
+ : new ArrayList<>(mExcludedTypes),
+ mHints == null
+ ? Collections.emptyList()
+ : Collections.unmodifiableList(new ArrayList<>(mHints)),
+ mIncludeTypesFromTextClassifier);
+ }
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index d5b9eb1d09dc..9ab963e372b7 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -393,7 +393,7 @@ public final class TextClassifierImpl implements TextClassifier {
actionsImpl.suggestActions(nativeConversation, null);
Collection<String> expectedTypes = resolveActionTypesFromRequest(request);
- List<ConversationActions.ConversationAction> conversationActions = new ArrayList<>();
+ List<ConversationAction> conversationActions = new ArrayList<>();
int maxSuggestions = nativeSuggestions.length;
if (request.getMaxSuggestions() > 0) {
maxSuggestions = Math.min(request.getMaxSuggestions(), nativeSuggestions.length);
@@ -405,7 +405,7 @@ public final class TextClassifierImpl implements TextClassifier {
continue;
}
conversationActions.add(
- new ConversationActions.ConversationAction.Builder(actionType)
+ new ConversationAction.Builder(actionType)
.setTextReply(nativeSuggestion.getResponseText())
.setConfidenceScore(nativeSuggestion.getScore())
.build());
@@ -445,10 +445,10 @@ public final class TextClassifierImpl implements TextClassifier {
private Collection<String> resolveActionTypesFromRequest(ConversationActions.Request request) {
List<String> defaultActionTypes =
- request.getHints().contains(ConversationActions.HINT_FOR_NOTIFICATION)
+ request.getHints().contains(ConversationActions.Request.HINT_FOR_NOTIFICATION)
? mSettings.getNotificationConversationActionTypes()
: mSettings.getInAppConversationActionTypes();
- return request.getTypeConfig().resolveTypes(defaultActionTypes);
+ return request.getTypeConfig().resolveEntityListModifications(defaultActionTypes);
}
private AnnotatorModel getAnnotatorImpl(LocaleList localeList)
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 9b9b77196a53..8e88c510ec31 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -23,6 +23,7 @@ import android.os.Parcelable;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.service.procstats.ProcessStatsAvailablePagesProto;
import android.service.procstats.ProcessStatsPackageProto;
import android.service.procstats.ProcessStatsSectionProto;
import android.text.format.DateFormat;
@@ -178,7 +179,7 @@ public final class ProcessStats implements Parcelable {
{"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 35;
+ private static final int PARCEL_VERSION = 36;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535454;
@@ -237,10 +238,11 @@ public final class ProcessStats implements Parcelable {
ArrayList<String> mIndexToCommonString;
private static final Pattern sPageTypeRegex = Pattern.compile(
- "^Node\\s+(\\d+),.*. type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$");
- private final ArrayList<Integer> mPageTypeZones = new ArrayList<Integer>();
- private final ArrayList<String> mPageTypeLabels = new ArrayList<String>();
- private final ArrayList<int[]> mPageTypeSizes = new ArrayList<int[]>();
+ "^Node\\s+(\\d+),.* zone\\s+(\\w+),.* type\\s+(\\w+)\\s+([\\s\\d]+?)\\s*$");
+ private final ArrayList<Integer> mPageTypeNodes = new ArrayList<>();
+ private final ArrayList<String> mPageTypeZones = new ArrayList<>();
+ private final ArrayList<String> mPageTypeLabels = new ArrayList<>();
+ private final ArrayList<int[]> mPageTypeSizes = new ArrayList<>();
public ProcessStats(boolean running) {
mRunning = running;
@@ -621,6 +623,7 @@ public final class ProcessStats implements Parcelable {
try {
reader = new BufferedReader(new FileReader("/proc/pagetypeinfo"));
final Matcher matcher = sPageTypeRegex.matcher("");
+ mPageTypeNodes.clear();
mPageTypeZones.clear();
mPageTypeLabels.clear();
mPageTypeSizes.clear();
@@ -631,16 +634,18 @@ public final class ProcessStats implements Parcelable {
}
matcher.reset(line);
if (matcher.matches()) {
- final Integer zone = Integer.valueOf(matcher.group(1), 10);
- if (zone == null) {
+ final Integer node = Integer.valueOf(matcher.group(1), 10);
+ if (node == null) {
continue;
}
- mPageTypeZones.add(zone);
- mPageTypeLabels.add(matcher.group(2));
- mPageTypeSizes.add(splitAndParseNumbers(matcher.group(3)));
+ mPageTypeNodes.add(node);
+ mPageTypeZones.add(matcher.group(2));
+ mPageTypeLabels.add(matcher.group(3));
+ mPageTypeSizes.add(splitAndParseNumbers(matcher.group(4)));
}
}
} catch (IOException ex) {
+ mPageTypeNodes.clear();
mPageTypeZones.clear();
mPageTypeLabels.clear();
mPageTypeSizes.clear();
@@ -935,7 +940,8 @@ public final class ProcessStats implements Parcelable {
final int NPAGETYPES = mPageTypeLabels.size();
out.writeInt(NPAGETYPES);
for (int i=0; i<NPAGETYPES; i++) {
- out.writeInt(mPageTypeZones.get(i));
+ out.writeInt(mPageTypeNodes.get(i));
+ out.writeString(mPageTypeZones.get(i));
out.writeString(mPageTypeLabels.get(i));
out.writeIntArray(mPageTypeSizes.get(i));
}
@@ -1244,6 +1250,8 @@ public final class ProcessStats implements Parcelable {
// Fragmentation info
final int NPAGETYPES = in.readInt();
+ mPageTypeNodes.clear();
+ mPageTypeNodes.ensureCapacity(NPAGETYPES);
mPageTypeZones.clear();
mPageTypeZones.ensureCapacity(NPAGETYPES);
mPageTypeLabels.clear();
@@ -1251,7 +1259,8 @@ public final class ProcessStats implements Parcelable {
mPageTypeSizes.clear();
mPageTypeSizes.ensureCapacity(NPAGETYPES);
for (int i=0; i<NPAGETYPES; i++) {
- mPageTypeZones.add(in.readInt());
+ mPageTypeNodes.add(in.readInt());
+ mPageTypeZones.add(in.readString());
mPageTypeLabels.add(in.readString());
mPageTypeSizes.add(in.createIntArray());
}
@@ -1764,7 +1773,8 @@ public final class ProcessStats implements Parcelable {
pw.println("Available pages by page size:");
final int NPAGETYPES = mPageTypeLabels.size();
for (int i=0; i<NPAGETYPES; i++) {
- pw.format("Zone %3d %14s ", mPageTypeZones.get(i), mPageTypeLabels.get(i));
+ pw.format("Node %3d Zone %7s %14s ", mPageTypeNodes.get(i), mPageTypeZones.get(i),
+ mPageTypeLabels.get(i));
final int[] sizes = mPageTypeSizes.get(i);
final int N = sizes == null ? 0 : sizes.length;
for (int j=0; j<N; j++) {
@@ -2095,6 +2105,9 @@ public final class ProcessStats implements Parcelable {
pw.print(",");
pw.print(mPageTypeZones.get(i));
pw.print(",");
+ // Wasn't included in original output.
+ //pw.print(mPageTypeNodes.get(i));
+ //pw.print(",");
final int[] sizes = mPageTypeSizes.get(i);
final int N = sizes == null ? 0 : sizes.length;
for (int j=0; j<N; j++) {
@@ -2135,6 +2148,20 @@ public final class ProcessStats implements Parcelable {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_PARTIAL);
}
+ final int NPAGETYPES = mPageTypeLabels.size();
+ for (int i = 0; i < NPAGETYPES; i++) {
+ final long token = proto.start(ProcessStatsSectionProto.AVAILABLE_PAGES);
+ proto.write(ProcessStatsAvailablePagesProto.NODE, mPageTypeNodes.get(i));
+ proto.write(ProcessStatsAvailablePagesProto.ZONE, mPageTypeZones.get(i));
+ proto.write(ProcessStatsAvailablePagesProto.LABEL, mPageTypeLabels.get(i));
+ final int[] sizes = mPageTypeSizes.get(i);
+ final int N = sizes == null ? 0 : sizes.length;
+ for (int j = 0; j < N; j++) {
+ proto.write(ProcessStatsAvailablePagesProto.PAGES_PER_ORDER, sizes[j]);
+ }
+ proto.end(token);
+ }
+
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
if ((section & REPORT_PROC_STATS) != 0) {
for (int ip = 0; ip < procMap.size(); ip++) {
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index eb7338a7ce58..876bd4fbfce4 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -8,7 +8,6 @@
#include "SkImageInfo.h"
#include "SkColor.h"
#include "SkColorSpace.h"
-#include "SkMatrix44.h"
#include "GraphicsJNI.h"
#include "SkStream.h"
@@ -356,8 +355,8 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors,
if (xyzD50 == nullptr || transferParameters == nullptr) {
colorSpace = SkColorSpace::MakeSRGB();
} else {
- SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
- SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
+ skcms_TransferFunction p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+ skcms_Matrix3x3 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
}
@@ -549,8 +548,7 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
if (skbitmap.colorType() == kRGBA_F16_SkColorType) {
// Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace
// for wide gamuts.
- auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
- SkColorSpace::kDCIP3_D65_Gamut);
+ auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType)
.makeColorSpace(std::move(cs));
SkBitmap p3;
@@ -568,11 +566,34 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle,
return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE;
}
+static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color,
+ const sk_sp<SkColorSpace>& colorSpace) {
+ SkPaint p;
+ p.setColor4f(color, colorSpace.get());
+ p.setBlendMode(SkBlendMode::kSrc);
+ SkCanvas canvas(bitmap);
+ canvas.drawPaint(p);
+}
+
static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) {
LocalScopedBitmap bitmap(bitmapHandle);
SkBitmap skBitmap;
bitmap->getSkBitmap(&skBitmap);
- skBitmap.eraseColor(color);
+ bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB());
+}
+
+static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle, jobject jColorSpace,
+ jfloat r, jfloat g, jfloat b, jfloat a) {
+ sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace);
+ if (GraphicsJNI::hasException(env)) {
+ return;
+ }
+
+ LocalScopedBitmap bitmap(bitmapHandle);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ SkColor4f color = SkColor4f{r, g, b, a};
+ bitmapErase(skBitmap, color, cs);
}
static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -717,7 +738,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {
#endif
// Dup the file descriptor so we can keep a reference to it after the Parcel
// is disposed.
- int dupFd = dup(blob.fd());
+ int dupFd = fcntl(blob.fd(), F_DUPFD_CLOEXEC, 0);
if (dupFd < 0) {
ALOGE("Error allocating dup fd. Error:%d", errno);
blob.release();
@@ -910,32 +931,32 @@ static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle,
SkColorSpace* colorSpace = bitmapHolder->info().colorSpace();
if (colorSpace == nullptr) return JNI_FALSE;
- SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+ skcms_Matrix3x3 xyzMatrix;
if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE;
jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL);
- xyz[0] = xyzMatrix.getFloat(0, 0);
- xyz[1] = xyzMatrix.getFloat(1, 0);
- xyz[2] = xyzMatrix.getFloat(2, 0);
- xyz[3] = xyzMatrix.getFloat(0, 1);
- xyz[4] = xyzMatrix.getFloat(1, 1);
- xyz[5] = xyzMatrix.getFloat(2, 1);
- xyz[6] = xyzMatrix.getFloat(0, 2);
- xyz[7] = xyzMatrix.getFloat(1, 2);
- xyz[8] = xyzMatrix.getFloat(2, 2);
+ xyz[0] = xyzMatrix.vals[0][0];
+ xyz[1] = xyzMatrix.vals[1][0];
+ xyz[2] = xyzMatrix.vals[2][0];
+ xyz[3] = xyzMatrix.vals[0][1];
+ xyz[4] = xyzMatrix.vals[1][1];
+ xyz[5] = xyzMatrix.vals[2][1];
+ xyz[6] = xyzMatrix.vals[0][2];
+ xyz[7] = xyzMatrix.vals[1][2];
+ xyz[8] = xyzMatrix.vals[2][2];
env->ReleaseFloatArrayElements(xyzArray, xyz, 0);
- SkColorSpaceTransferFn transferParams;
+ skcms_TransferFunction transferParams;
if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE;
jfloat* params = env->GetFloatArrayElements(paramsArray, NULL);
- params[0] = transferParams.fA;
- params[1] = transferParams.fB;
- params[2] = transferParams.fC;
- params[3] = transferParams.fD;
- params[4] = transferParams.fE;
- params[5] = transferParams.fF;
- params[6] = transferParams.fG;
+ params[0] = transferParams.a;
+ params[1] = transferParams.b;
+ params[2] = transferParams.c;
+ params[3] = transferParams.d;
+ params[4] = transferParams.e;
+ params[5] = transferParams.f;
+ params[6] = transferParams.g;
env->ReleaseFloatArrayElements(paramsArray, params, 0);
return JNI_TRUE;
@@ -1121,8 +1142,8 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic
static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer,
jfloatArray xyzD50, jobject transferParameters) {
- SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
- SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
+ skcms_TransferFunction p = GraphicsJNI::getNativeTransferParameters(env, transferParameters);
+ skcms_Matrix3x3 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50);
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix);
AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env,
hardwareBuffer);
@@ -1183,6 +1204,7 @@ static const JNINativeMethod gBitmapMethods[] = {
{ "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(JI)V", (void*)Bitmap_erase },
+ { "nativeErase", "(JLandroid/graphics/ColorSpace;FFFF)V", (void*)Bitmap_eraseLong },
{ "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes },
{ "nativeConfig", "(J)I", (void*)Bitmap_config },
{ "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha },
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 67d0c8aced61..9e74b883a298 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -424,30 +424,30 @@ jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
///////////////////////////////////////////////////////////////////////////////
-SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
- SkColorSpaceTransferFn p;
- p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
- p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
- p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
- p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
- p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
- p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
- p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
+skcms_TransferFunction GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) {
+ skcms_TransferFunction p;
+ p.a = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID);
+ p.b = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID);
+ p.c = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID);
+ p.d = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID);
+ p.e = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID);
+ p.f = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID);
+ p.g = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID);
return p;
}
-SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
- SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor);
+skcms_Matrix3x3 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) {
+ skcms_Matrix3x3 xyzMatrix;
jfloat* array = env->GetFloatArrayElements(xyzD50, NULL);
- xyzMatrix.setFloat(0, 0, array[0]);
- xyzMatrix.setFloat(1, 0, array[1]);
- xyzMatrix.setFloat(2, 0, array[2]);
- xyzMatrix.setFloat(0, 1, array[3]);
- xyzMatrix.setFloat(1, 1, array[4]);
- xyzMatrix.setFloat(2, 1, array[5]);
- xyzMatrix.setFloat(0, 2, array[6]);
- xyzMatrix.setFloat(1, 2, array[7]);
- xyzMatrix.setFloat(2, 2, array[8]);
+ xyzMatrix.vals[0][0] = array[0];
+ xyzMatrix.vals[1][0] = array[1];
+ xyzMatrix.vals[2][0] = array[2];
+ xyzMatrix.vals[0][1] = array[3];
+ xyzMatrix.vals[1][1] = array[4];
+ xyzMatrix.vals[2][1] = array[5];
+ xyzMatrix.vals[0][2] = array[6];
+ xyzMatrix.vals[1][2] = array[7];
+ xyzMatrix.vals[2][2] = array[8];
env->ReleaseFloatArrayElements(xyzD50, array, 0);
return xyzMatrix;
}
@@ -456,12 +456,14 @@ sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorS
if (colorSpace == nullptr) return nullptr;
if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) {
doThrowIAE(env, "The color space must be an RGB color space");
+ return nullptr;
}
jobject transferParams = env->CallObjectMethod(colorSpace,
gColorSpaceRGB_getTransferParametersMethodID);
if (transferParams == nullptr) {
doThrowIAE(env, "The color space must use an ICC parametric transfer function");
+ return nullptr;
}
jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class,
@@ -472,8 +474,8 @@ sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorS
jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50,
gColorSpaceRGB_getTransformMethodID);
- SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
- SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams);
+ skcms_Matrix3x3 xyzMatrix = getNativeXYZMatrix(env, xyzD50);
+ skcms_TransferFunction transferFunction = getNativeTransferParameters(env, transferParams);
return SkColorSpace::MakeRGB(transferFunction, xyzMatrix);
}
@@ -499,30 +501,30 @@ jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColor
} else if (decodeColorSpace.get() != nullptr) {
// Try to match against known RGB color spaces using the CIE XYZ D50
// conversion matrix and numerical transfer function parameters
- SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+ skcms_Matrix3x3 xyzMatrix;
LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
- SkColorSpaceTransferFn transferParams;
+ skcms_TransferFunction transferParams;
// We can only handle numerical transfer functions at the moment
LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
jobject params = env->NewObject(gTransferParameters_class,
gTransferParameters_constructorMethodID,
- transferParams.fA, transferParams.fB, transferParams.fC,
- transferParams.fD, transferParams.fE, transferParams.fF,
- transferParams.fG);
+ transferParams.a, transferParams.b, transferParams.c,
+ transferParams.d, transferParams.e, transferParams.f,
+ transferParams.g);
jfloatArray xyzArray = env->NewFloatArray(9);
jfloat xyz[9] = {
- xyzMatrix.getFloat(0, 0),
- xyzMatrix.getFloat(1, 0),
- xyzMatrix.getFloat(2, 0),
- xyzMatrix.getFloat(0, 1),
- xyzMatrix.getFloat(1, 1),
- xyzMatrix.getFloat(2, 1),
- xyzMatrix.getFloat(0, 2),
- xyzMatrix.getFloat(1, 2),
- xyzMatrix.getFloat(2, 2)
+ xyzMatrix.vals[0][0],
+ xyzMatrix.vals[1][0],
+ xyzMatrix.vals[2][0],
+ xyzMatrix.vals[0][1],
+ xyzMatrix.vals[1][1],
+ xyzMatrix.vals[2][1],
+ xyzMatrix.vals[0][2],
+ xyzMatrix.vals[1][2],
+ xyzMatrix.vals[2][2]
};
env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index b0bd68336e08..699d153874a2 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -10,7 +10,6 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkColorSpace.h"
-#include "SkMatrix44.h"
#include <jni.h>
#include <hwui/Canvas.h>
#include <hwui/Bitmap.h>
@@ -101,8 +100,8 @@ public:
int srcStride, int x, int y, int width, int height,
SkBitmap* dstBitmap);
- static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams);
- static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
+ static skcms_TransferFunction getNativeTransferParameters(JNIEnv* env, jobject transferParams);
+ static skcms_Matrix3x3 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50);
static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace);
static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace,
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 7ef06dc54945..3b59321024fd 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -473,7 +473,7 @@ static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jclass clazz, j
if (parcel != NULL) {
int fd = parcel->readFileDescriptor();
if (fd < 0) return NULL;
- fd = dup(fd);
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
if (fd < 0) return NULL;
return jniCreateFileDescriptor(env, fd);
}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7b564ae162ce..4101c04162af 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -44,6 +44,8 @@
#include "androidfw/MutexGuard.h"
#include "androidfw/PosixUtils.h"
#include "androidfw/ResourceTypes.h"
+#include "androidfw/ResourceUtils.h"
+
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/JNIHelp.h"
@@ -975,34 +977,7 @@ static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, j
return nullptr;
}
- std::string result;
- if (name.package != nullptr) {
- result.append(name.package, name.package_len);
- }
-
- if (name.type != nullptr || name.type16 != nullptr) {
- if (!result.empty()) {
- result += ":";
- }
-
- if (name.type != nullptr) {
- result.append(name.type, name.type_len);
- } else {
- result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
- }
- }
-
- if (name.entry != nullptr || name.entry16 != nullptr) {
- if (!result.empty()) {
- result += "/";
- }
-
- if (name.entry != nullptr) {
- result.append(name.entry, name.entry_len);
- } else {
- result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
- }
- }
+ std::string result = ToFormattedResourceString(&name);
return env->NewStringUTF(result.c_str());
}
@@ -1049,6 +1024,26 @@ static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong p
return nullptr;
}
+static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
+ jclass /*clazz*/,
+ jlong ptr,
+ jboolean enabled) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ assetmanager->SetResourceResolutionLoggingEnabled(enabled);
+}
+
+static jstring NativeGetLastResourceResolution(JNIEnv* env,
+ jclass /*clazz*/,
+ jlong ptr) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ std::string resolution = assetmanager->GetLastResourceResolution();
+ if (resolution.empty()) {
+ return nullptr;
+ } else {
+ return env->NewStringUTF(resolution.c_str());
+ }
+}
+
static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
jboolean exclude_system) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
@@ -1452,6 +1447,10 @@ static const JNINativeMethod gAssetManagerMethods[] = {
{"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
{"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
{"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
+ {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
+ (void*) NativeSetResourceResolutionLoggingEnabled},
+ {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
+ (void*) NativeGetLastResourceResolution},
{"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
{"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
(void*)NativeGetSizeConfigurations},
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index bd87dcc325a8..41e00b9461c8 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -33,6 +33,7 @@
// Static whitelist of open paths that the zygote is allowed to keep open.
static const char* kPathWhitelist[] = {
+ "/apex/com.android.conscrypt/javalib/conscrypt.jar",
"/dev/null",
"/dev/socket/zygote",
"/dev/socket/zygote_secondary",
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 3e1c5a334184..2f2f62392157 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -29,6 +29,12 @@ enum Action {
// ACTION: Settings > Any preference is changed
ACTION_SETTINGS_PREFERENCE_CHANGE = 853;
+
+ // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
+ ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
+
+ // ACTION: Tap & Pay -> Default Application Setting -> Use Default
+ ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
}
/**
diff --git a/core/proto/android/service/package.proto b/core/proto/android/service/package.proto
index 4ecf52ce5012..7f96d701cdbf 100644
--- a/core/proto/android/service/package.proto
+++ b/core/proto/android/service/package.proto
@@ -111,6 +111,7 @@ message PackageProto {
optional EnabledState enabled_state = 7;
optional string last_disabled_app_caller = 8;
optional string suspending_package = 9;
+ optional int32 distraction_flags = 10;
}
// Name of package. e.g. "com.android.providers.telephony".
diff --git a/core/proto/android/service/procstats.proto b/core/proto/android/service/procstats.proto
index 71ebcc1e3659..da801ffcc99a 100644
--- a/core/proto/android/service/procstats.proto
+++ b/core/proto/android/service/procstats.proto
@@ -43,7 +43,7 @@ message ProcessStatsServiceDumpProto {
* Data model from /frameworks/base/core/java/com/android/internal/app/procstats/ProcessStats.java
* This proto is defined based on the writeToParcel method.
*
- * Next Tag: 10
+ * Next Tag: 11
*/
message ProcessStatsSectionProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -76,6 +76,9 @@ message ProcessStatsSectionProto {
}
repeated Status status = 7;
+ // Number of pages available of various types and sizes, representation fragmentation.
+ repeated ProcessStatsAvailablePagesProto available_pages = 10;
+
// Stats for each process.
repeated ProcessStatsProto process_stats = 8;
@@ -83,6 +86,24 @@ message ProcessStatsSectionProto {
repeated ProcessStatsPackageProto package_stats = 9;
}
+// Next Tag: 5
+message ProcessStatsAvailablePagesProto {
+ option (android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ // Node these pages are in (as per /proc/pagetypeinfo)
+ optional int32 node = 1;
+
+ // Zone these pages are in (as per /proc/pagetypeinfo)
+ optional string zone = 2;
+
+ // Label for the type of these pages (as per /proc/pagetypeinfo)
+ optional string label = 3;
+
+ // Distribution of number of pages available by order size. First entry in array is
+ // order 0, second is order 1, etc. Each order increase is a doubling of page size.
+ repeated int32 pages_per_order = 4;
+}
+
// Next Tag: 10
message ProcessStatsStateProto {
option (android.msg_privacy).dest = DEST_AUTOMATIC;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8147b4a2a009..2f3a4910bf83 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -51,6 +51,7 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
+ <protected-broadcast android:name="android.intent.action.DISTRACTING_PACKAGES_CHANGED" />
<protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" />
<protected-broadcast android:name="android.intent.action.UID_REMOVED" />
<protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
@@ -2268,6 +2269,11 @@
<permission android:name="android.permission.START_ANY_ACTIVITY"
android:protectionLevel="signature" />
+ <!-- Allows an application to start activities from background
+ @hide -->
+ <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
+ android:protectionLevel="signature|privileged|vendorPrivileged|oem" />
+
<!-- @SystemApi Must be required by activities that handle the intent action
{@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1feb59a52ad1..d40f01c7c960 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -929,9 +929,6 @@
in hardware. -->
<bool name="config_setColorTransformAccelerated">false</bool>
- <!-- Boolean indicating whether display white balance is supported. -->
- <bool name="config_displayWhiteBalanceAvailable">false</bool>
-
<!-- Control whether Night display is available. This should only be enabled on devices
that have a HWC implementation that can apply the matrix passed to setColorTransform
without impacting power, performance, and app compatibility (e.g. protected content). -->
@@ -987,6 +984,44 @@
<!-- B y-intercept --> <item>-0.198650895</item>
</string-array>
+ <!-- Boolean indicating whether display white balance is supported. -->
+ <bool name="config_displayWhiteBalanceAvailable">false</bool>
+
+ <!-- Minimum color temperature, in Kelvin, supported by display white balance. -->
+ <integer name="config_displayWhiteBalanceColorTemperatureMin">4000</integer>
+
+ <!-- Maximum color temperature, in Kelvin, supported by display white balance. -->
+ <integer name="config_displayWhiteBalanceColorTemperatureMax">8000</integer>
+
+ <!-- Default color temperature, in Kelvin, used by display white balance. -->
+ <integer name="config_displayWhiteBalanceColorTemperatureDefault">6500</integer>
+
+ <!-- The display primaries, in CIE1931 XYZ color space, for display
+ white balance to use in its calculations. -->
+ <string-array name="config_displayWhiteBalanceDisplayPrimaries">
+ <!-- Red X --> <item>0.412315</item>
+ <!-- Red Y --> <item>0.212600</item>
+ <!-- Red Z --> <item>0.019327</item>
+ <!-- Green X --> <item>0.357600</item>
+ <!-- Green Y --> <item>0.715200</item>
+ <!-- Green Z --> <item>0.119200</item>
+ <!-- Blue X --> <item>0.180500</item>
+ <!-- Blue Y --> <item>0.072200</item>
+ <!-- Blue Z --> <item>0.950633</item>
+ <!-- White X --> <item>0.950456</item>
+ <!-- White Y --> <item>1.000000</item>
+ <!-- White Z --> <item>1.089058</item>
+ </string-array>
+
+ <!-- The nominal white coordinates, in CIE1931 XYZ color space, for Display White Balance to
+ use in its calculations. AWB will adapt this white point to the target ambient white
+ point. -->
+ <string-array name="config_displayWhiteBalanceDisplayNominalWhite">
+ <!-- Nominal White X --> <item>0.950456</item>
+ <!-- Nominal White Y --> <item>1.000000</item>
+ <!-- Nominal White Z --> <item>1.089058</item>
+ </string-array>
+
<!-- Indicate available ColorDisplayController.COLOR_MODE_xxx. -->
<integer-array name="config_availableColorModes">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 010accf19d18..a1ef0d5cc93b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3042,6 +3042,13 @@
<java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" />
<java-symbol type="array" name="config_availableColorModes" />
+ <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMax" />
+ <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
+ <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+
<!-- Default first user restrictions -->
<java-symbol type="array" name="config_defaultFirstUserRestrictions" />
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 82eaf88fb07a..ec6101c09b7b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -377,10 +377,10 @@ public class TextClassifierTest {
ConversationActions.Message.PERSON_USER_REMOTE)
.setText("Where are you?")
.build();
- ConversationActions.TypeConfig typeConfig =
- new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+ TextClassifier.EntityConfig typeConfig =
+ new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
.setIncludedTypes(
- Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+ Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
.build();
ConversationActions.Request request =
new ConversationActions.Request.Builder(Collections.singletonList(message))
@@ -391,10 +391,10 @@ public class TextClassifierTest {
ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
assertTrue(conversationActions.getConversationActions().size() > 0);
assertTrue(conversationActions.getConversationActions().size() == 1);
- for (ConversationActions.ConversationAction conversationAction :
+ for (ConversationAction conversationAction :
conversationActions.getConversationActions()) {
assertThat(conversationAction,
- isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
+ isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
}
}*/
@@ -406,10 +406,10 @@ public class TextClassifierTest {
ConversationActions.Message.PERSON_USER_REMOTE)
.setText("Where are you?")
.build();
- ConversationActions.TypeConfig typeConfig =
- new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+ TextClassifier.EntityConfig typeConfig =
+ new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
.setIncludedTypes(
- Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+ Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
.build();
ConversationActions.Request request =
new ConversationActions.Request.Builder(Collections.singletonList(message))
@@ -418,10 +418,10 @@ public class TextClassifierTest {
ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
assertTrue(conversationActions.getConversationActions().size() > 1);
- for (ConversationActions.ConversationAction conversationAction :
+ for (ConversationAction conversationAction :
conversationActions.getConversationActions()) {
assertThat(conversationAction,
- isConversationAction(ConversationActions.TYPE_TEXT_REPLY));
+ isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
}
}
@@ -524,20 +524,19 @@ public class TextClassifierTest {
};
}
- private static Matcher<ConversationActions.ConversationAction> isConversationAction(
- String actionType) {
- return new BaseMatcher<ConversationActions.ConversationAction>() {
+ private static Matcher<ConversationAction> isConversationAction(String actionType) {
+ return new BaseMatcher<ConversationAction>() {
@Override
public boolean matches(Object o) {
- if (!(o instanceof ConversationActions.ConversationAction)) {
+ if (!(o instanceof ConversationAction)) {
return false;
}
- ConversationActions.ConversationAction conversationAction =
- (ConversationActions.ConversationAction) o;
+ ConversationAction conversationAction =
+ (ConversationAction) o;
if (!actionType.equals(conversationAction.getType())) {
return false;
}
- if (ConversationActions.TYPE_TEXT_REPLY.equals(actionType)) {
+ if (ConversationAction.TYPE_TEXT_REPLY.equals(actionType)) {
if (conversationAction.getTextReply() == null) {
return false;
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
index 344f79dcc48e..0597a89e87d4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -26,7 +26,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.metrics.LogMaker;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import android.view.textclassifier.ConversationActions;
+import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassifierEvent;
import android.view.textclassifier.TextClassifierEventTronLogger;
@@ -69,7 +69,7 @@ public class TextClassifierEventTronLoggerTest {
new TextClassifierEvent.Builder(
TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS,
TextClassifierEvent.TYPE_SMART_ACTION)
- .setEntityType(ConversationActions.TYPE_CALL_PHONE)
+ .setEntityType(ConversationAction.TYPE_CALL_PHONE)
.setEventTime(EVENT_TIME)
.setEventContext(textClassificationContext)
.build();
@@ -84,7 +84,7 @@ public class TextClassifierEventTronLoggerTest {
assertThat(logMaker.getType()).isEqualTo(
ACTION_TEXT_SELECTION_SMART_SHARE);
assertThat(logMaker.getTaggedData(FIELD_SELECTION_ENTITY_TYPE))
- .isEqualTo(ConversationActions.TYPE_CALL_PHONE);
+ .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME))
.isEqualTo(EVENT_TIME);
assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 0bffa387489b..6ce81481c1d7 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -41,7 +41,39 @@ prebuilt_etc {
src: "privapp-permissions-platform.xml",
required: [
"privapp_whitelist_com.android.settings.intelligence",
- ]
+ ],
+}
+
+prebuilt_etc {
+ name: "privapp_whitelist_com.android.carrierconfig",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.carrierconfig.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
+ name: "privapp_whitelist_com.android.contacts",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.contacts.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
+ name: "privapp_whitelist_com.android.launcher3",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.launcher3.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
+ name: "privapp_whitelist_com.android.provision",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.provision.xml",
+ filename_from_src: true,
}
prebuilt_etc {
@@ -60,6 +92,14 @@ prebuilt_etc {
}
prebuilt_etc {
+ name: "privapp_whitelist_com.android.storagemanager",
+ product_specific: true,
+ sub_dir: "permissions",
+ src: "com.android.storagemanager.xml",
+ filename_from_src: true,
+}
+
+prebuilt_etc {
name: "privapp_whitelist_com.android.systemui",
product_specific: true,
sub_dir: "permissions",
diff --git a/data/etc/com.android.carrierconfig.xml b/data/etc/com.android.carrierconfig.xml
new file mode 100644
index 000000000000..17efb0315040
--- /dev/null
+++ b/data/etc/com.android.carrierconfig.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.carrierconfig">
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.contacts.xml b/data/etc/com.android.contacts.xml
new file mode 100644
index 000000000000..78eae40348e6
--- /dev/null
+++ b/data/etc/com.android.contacts.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.contacts">
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml
new file mode 100644
index 000000000000..337e153722ac
--- /dev/null
+++ b/data/etc/com.android.launcher3.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.launcher3">
+ <permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
+ <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.provision.xml b/data/etc/com.android.provision.xml
new file mode 100644
index 000000000000..05404ef73732
--- /dev/null
+++ b/data/etc/com.android.provision.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.provision">
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.storagemanager.xml b/data/etc/com.android.storagemanager.xml
new file mode 100644
index 000000000000..e85a82c983df
--- /dev/null
+++ b/data/etc/com.android.storagemanager.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 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
+ -->
+<permissions>
+ <privapp-permissions package="com.android.storagemanager">
+ <permission name="android.permission.DELETE_PACKAGES"/>
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.PACKAGE_USAGE_STATS"/>
+ <permission name="android.permission.USE_RESERVED_DISK"/>
+ <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 221708b8c94d..3562a8f81408 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -44,6 +44,7 @@
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REAL_GET_TASKS"/>
<permission name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"/>
+ <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
<permission name="android.permission.START_ACTIVITY_AS_CALLER"/>
<permission name="android.permission.START_TASKS_FROM_RECENTS"/>
<permission name="android.permission.STATUS_BAR"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 393a2a6fee03..597d14ac286e 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -33,10 +33,6 @@ applications that come with the platform
<permission name="android.permission.CRYPT_KEEPER"/>
</privapp-permissions>
- <privapp-permissions package="com.android.carrierconfig">
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.cellbroadcastreceiver">
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
@@ -45,11 +41,6 @@ applications that come with the platform
<permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
</privapp-permissions>
- <privapp-permissions package="com.android.contacts">
- <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
- <permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.defcontainer">
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM"/>
<permission name="android.permission.ALLOCATE_AGGRESSIVE"/>
@@ -79,12 +70,6 @@ applications that come with the platform
<permission name="android.permission.WRITE_MEDIA_STORAGE"/>
</privapp-permissions>
- <privapp-permissions package="com.android.launcher3">
- <permission name="android.permission.BIND_APPWIDGET"/>
- <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
- <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.location.fused">
<permission name="android.permission.INSTALL_LOCATION_PROVIDER"/>
</privapp-permissions>
@@ -238,10 +223,6 @@ applications that come with the platform
<permission name="android.permission.USE_RESERVED_DISK"/>
</privapp-permissions>
- <privapp-permissions package="com.android.provision">
- <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.mainline.networkstack">
<permission name="android.permission.ACCESS_NETWORK_CONDITIONS"/>
<permission name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"/>
@@ -335,6 +316,7 @@ applications that come with the platform
<permission name="android.permission.SET_TIME"/>
<permission name="android.permission.SET_TIME_ZONE"/>
<permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES"/>
+ <permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
<permission name="android.permission.START_TASKS_FROM_RECENTS" />
<permission name="android.permission.STOP_APP_SWITCHES"/>
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
@@ -349,15 +331,6 @@ applications that come with the platform
<permission name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
</privapp-permissions>
- <privapp-permissions package="com.android.storagemanager">
- <permission name="android.permission.DELETE_PACKAGES"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.PACKAGE_USAGE_STATS"/>
- <permission name="android.permission.USE_RESERVED_DISK"/>
- <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- </privapp-permissions>
-
<privapp-permissions package="com.android.tv">
<permission name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"/>
<permission name="android.permission.DVB_DEVICE"/>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index ca9dc475f7a1..65aaba17a55d 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Canvas.VertexMode;
+import android.graphics.text.MeasuredText;
import android.text.GraphicsOperations;
import android.text.MeasuredParagraph;
import android.text.PrecomputedText;
@@ -554,14 +555,12 @@ public abstract class BaseCanvas {
final int paraStart = pt.getParagraphStart(paraIndex);
final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
// Only support the text in the same paragraph.
- nDrawTextRun(mNativeCanvasWrapper,
- mp.getChars(),
- start - paraStart,
- end - start,
- contextStart - paraStart,
- contextEnd - contextStart,
- x, y, isRtl, paint.getNativeInstance(),
- mp.getMeasuredText().getNativePtr());
+ drawTextRun(mp.getMeasuredText(),
+ start - paraStart,
+ end - paraStart,
+ contextStart - paraStart,
+ contextEnd - paraStart,
+ x, y, isRtl, paint);
return;
}
}
@@ -576,6 +575,14 @@ public abstract class BaseCanvas {
}
}
+ public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
+ int contextStart, int contextEnd, float x, float y, boolean isRtl,
+ @NonNull Paint paint) {
+ nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
+ contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
+ measuredText.getNativePtr());
+ }
+
public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 901c2116884b..4f6093500cad 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -20,6 +20,7 @@ import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.graphics.text.MeasuredText;
import android.text.GraphicsOperations;
import android.text.MeasuredParagraph;
import android.text.PrecomputedText;
@@ -522,14 +523,12 @@ public class BaseRecordingCanvas extends Canvas {
final int paraStart = pt.getParagraphStart(paraIndex);
final MeasuredParagraph mp = pt.getMeasuredParagraph(paraIndex);
// Only support if the target is in the same paragraph.
- nDrawTextRun(mNativeCanvasWrapper,
- mp.getChars(),
+ drawTextRun(mp.getMeasuredText(),
start - paraStart,
- end - start,
+ end - paraStart,
contextStart - paraStart,
- contextEnd - contextStart,
- x, y, isRtl, paint.getNativeInstance(),
- mp.getMeasuredText().getNativePtr());
+ contextEnd - paraStart,
+ x, y, isRtl, paint);
return;
}
}
@@ -545,6 +544,15 @@ public class BaseRecordingCanvas extends Canvas {
}
@Override
+ public void drawTextRun(@NonNull MeasuredText measuredText, int start, int end,
+ int contextStart, int contextEnd, float x, float y, boolean isRtl,
+ @NonNull Paint paint) {
+ nDrawTextRun(mNativeCanvasWrapper, measuredText.getChars(), start, end - start,
+ contextStart, contextEnd - contextStart, x, y, isRtl, paint.getNativeInstance(),
+ measuredText.getNativePtr());
+ }
+
+ @Override
public final void drawVertices(@NonNull VertexMode mode, int vertexCount,
@NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset,
@Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset,
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 790b37eec4c5..30f0bfa68b4a 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -18,9 +18,11 @@ package android.graphics;
import android.annotation.CheckResult;
import android.annotation.ColorInt;
+import android.annotation.ColorLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import android.content.res.ResourcesImpl;
@@ -1780,6 +1782,30 @@ public final class Bitmap implements Parcelable {
}
/**
+ * Fills the bitmap's pixels with the specified {@link Color}.
+ *
+ * @throws IllegalStateException if the bitmap is not mutable.
+ * @throws IllegalArgumentException if the color space encoded in the long
+ * is invalid or unknown.
+ *
+ * @hide pending API approval
+ */
+ @TestApi
+ public void eraseColor(@ColorLong long c) {
+ checkRecycled("Can't erase a recycled bitmap");
+ if (!isMutable()) {
+ throw new IllegalStateException("cannot erase immutable bitmaps");
+ }
+
+ ColorSpace cs = Color.colorSpace(c);
+ float r = Color.red(c);
+ float g = Color.green(c);
+ float b = Color.blue(c);
+ float a = Color.alpha(c);
+ nativeErase(mNativePtr, cs, r, g, b, a);
+ }
+
+ /**
* Returns the {@link Color} at the specified location. Throws an exception
* if x or y are out of bounds (negative or >= to the width or height
* respectively). The returned color is a non-premultiplied ARGB value in
@@ -2123,6 +2149,8 @@ public final class Bitmap implements Parcelable {
int quality, OutputStream stream,
byte[] tempStorage);
private static native void nativeErase(long nativeBitmap, int color);
+ private static native void nativeErase(long nativeBitmap, ColorSpace cs,
+ float r, float g, float b, float a);
private static native int nativeRowBytes(long nativeBitmap);
private static native int nativeConfig(long nativeBitmap);
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 63a806e53556..8c1bae2a0527 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.UnsupportedAppUsage;
+import android.graphics.text.MeasuredText;
import android.os.Build;
import dalvik.annotation.optimization.CriticalNative;
@@ -2122,7 +2123,8 @@ public class Canvas extends BaseCanvas {
* the text next to it.
* <p>
* All text outside the range {@code contextStart..contextEnd} is ignored. The text between
- * {@code start} and {@code end} will be laid out and drawn.
+ * {@code start} and {@code end} will be laid out and drawn. The context range is useful for
+ * contextual shaping, e.g. Kerning, Arabic contextural form.
* <p>
* The direction of the run is explicitly specified by {@code isRtl}. Thus, this method is
* suitable only for runs of a single direction. Alignment of the text is as determined by the
@@ -2151,6 +2153,31 @@ public class Canvas extends BaseCanvas {
}
/**
+ * Draw a run of text, all in a single direction, with optional context for complex text
+ * shaping.
+ * <p>
+ * See {@link #drawTextRun(CharSequence, int, int, int, int, float, float, boolean, Paint)} for
+ * more details. This method uses a {@link MeasuredText} rather than CharSequence to represent
+ * the string.
+ *
+ * @param text the text to render
+ * @param start the start of the text to render. Data before this position can be used for
+ * shaping context.
+ * @param end the end of the text to render. Data at or after this position can be used for
+ * shaping context.
+ * @param contextStart the index of the start of the shaping context
+ * @param contextEnd the index of the end of the shaping context
+ * @param x the x position at which to draw the text
+ * @param y the y position at which to draw the text
+ * @param isRtl whether the run is in RTL direction
+ * @param paint the paint
+ */
+ public void drawTextRun(@NonNull MeasuredText text, int start, int end, int contextStart,
+ int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
+ super.drawTextRun(text, start, end, contextStart, contextEnd, x, y, isRtl, paint);
+ }
+
+ /**
* Draw the array of vertices, interpreted as triangles (based on mode). The verts array is
* required, and specifies the x,y pairs for each vertex. If texs is non-null, then it is used
* to specify the coordinate in shader coordinates to use at each vertex (the paint must have a
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 95317a4d0bf2..9fa70a5ab19c 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1661,10 +1661,12 @@ public abstract class ColorSpace {
* @param rhs 3x3 matrix, as a non-null array of 9 floats
* @return A new array of 9 floats containing the result of the multiplication
* of rhs by lhs
+ *
+ * @hide
*/
@NonNull
@Size(9)
- private static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
+ public static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) {
float[] r = new float[9];
r[0] = lhs[0] * rhs[0] + lhs[3] * rhs[1] + lhs[6] * rhs[2];
r[1] = lhs[1] * rhs[0] + lhs[4] * rhs[1] + lhs[7] * rhs[2];
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index ad9ec02648b1..3c35d9b33fc8 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -20,8 +20,9 @@
#include <algorithm>
#include <iterator>
-#include <set>
#include <map>
+#include <set>
+#include <sstream>
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
@@ -372,6 +373,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
uint32_t best_offset = 0u;
uint32_t type_flags = 0u;
+ Resolution::Step::Type resolution_type;
+ std::vector<Resolution::Step> resolution_steps;
+
// If desired_config is the same as the set configuration, then we can use our filtered list
// and we don't need to match the configurations, since they already matched.
const bool use_fast_path = desired_config == &configuration_;
@@ -403,8 +407,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// If the package is an overlay, then even configurations that are the same MUST be chosen.
const bool package_is_overlay = loaded_package->IsOverlay();
- const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
if (use_fast_path) {
+ const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
const size_t type_count = candidate_configs.size();
for (uint32_t i = 0; i < type_count; i++) {
@@ -412,21 +416,34 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
// We can skip calling ResTable_config::match() because we know that all candidate
// configurations that do NOT match have been filtered-out.
- if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
- (package_is_overlay && this_config.compare(*best_config) == 0)) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const ResTable_type* type_chunk = filtered_group.types[i];
- const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
+ if (best_config == nullptr) {
+ resolution_type = Resolution::Step::Type::INITIAL;
+ } else if (this_config.isBetterThan(*best_config, desired_config)) {
+ resolution_type = Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID;
+ } else {
+ continue;
+ }
+
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const ResTable_type* type = filtered_group.types[i];
+ const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
- best_cookie = cookie;
- best_package = loaded_package;
- best_type = type_chunk;
- best_config = &this_config;
- best_offset = offset;
+ best_cookie = cookie;
+ best_package = loaded_package;
+ best_type = type;
+ best_config = &this_config;
+ best_offset = offset;
+
+ if (resource_resolution_logging_enabled_) {
+ resolution_steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
}
}
} else {
@@ -440,23 +457,38 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
ResTable_config this_config;
this_config.copyFromDtoH((*iter)->config);
- if (this_config.match(*desired_config)) {
- if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
- (package_is_overlay && this_config.compare(*best_config) == 0)) {
- // The configuration matches and is better than the previous selection.
- // Find the entry value if it exists for this configuration.
- const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- continue;
- }
+ if (!this_config.match(*desired_config)) {
+ continue;
+ }
- best_cookie = cookie;
- best_package = loaded_package;
- best_type = *iter;
- best_config_copy = this_config;
- best_config = &best_config_copy;
- best_offset = offset;
- }
+ if (best_config == nullptr) {
+ resolution_type = Resolution::Step::Type::INITIAL;
+ } else if (this_config.isBetterThan(*best_config, desired_config)) {
+ resolution_type = Resolution::Step::Type::BETTER_MATCH;
+ } else if (package_is_overlay && this_config.compare(*best_config) == 0) {
+ resolution_type = Resolution::Step::Type::OVERLAID;
+ } else {
+ continue;
+ }
+
+ // The configuration matches and is better than the previous selection.
+ // Find the entry value if it exists for this configuration.
+ const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
+ if (offset == ResTable_type::NO_ENTRY) {
+ continue;
+ }
+
+ best_cookie = cookie;
+ best_package = loaded_package;
+ best_type = *iter;
+ best_config_copy = this_config;
+ best_config = &best_config_copy;
+ best_offset = offset;
+
+ if (resource_resolution_logging_enabled_) {
+ resolution_steps.push_back(Resolution::Step{resolution_type,
+ this_config.toString(),
+ &loaded_package->GetPackageName()});
}
}
}
@@ -478,9 +510,95 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri
out_entry->entry_string_ref =
StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+
+ if (resource_resolution_logging_enabled_) {
+ last_resolution.resid = resid;
+ last_resolution.cookie = best_cookie;
+ last_resolution.steps = resolution_steps;
+
+ // Cache only the type/entry refs since that's all that's needed to build name
+ last_resolution.type_string_ref =
+ StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
+ last_resolution.entry_string_ref =
+ StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+ }
+
return best_cookie;
}
+void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) {
+ resource_resolution_logging_enabled_ = enabled;
+
+ if (!enabled) {
+ last_resolution.cookie = kInvalidCookie;
+ last_resolution.resid = 0;
+ last_resolution.steps.clear();
+ last_resolution.type_string_ref = StringPoolRef();
+ last_resolution.entry_string_ref = StringPoolRef();
+ }
+}
+
+std::string AssetManager2::GetLastResourceResolution() const {
+ if (!resource_resolution_logging_enabled_) {
+ LOG(ERROR) << "Must enable resource resolution logging before getting path.";
+ return std::string();
+ }
+
+ auto cookie = last_resolution.cookie;
+ if (cookie == kInvalidCookie) {
+ LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
+ return std::string();
+ }
+
+ uint32_t resid = last_resolution.resid;
+ std::vector<Resolution::Step>& steps = last_resolution.steps;
+
+ ResourceName resource_name;
+ std::string resource_name_string;
+
+ const LoadedPackage* package =
+ apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+
+ if (package != nullptr) {
+ ToResourceName(last_resolution.type_string_ref,
+ last_resolution.entry_string_ref,
+ package,
+ &resource_name);
+ resource_name_string = ToFormattedResourceString(&resource_name);
+ }
+
+ std::stringstream log_stream;
+ log_stream << base::StringPrintf("Resolution for 0x%08x ", resid)
+ << resource_name_string
+ << "\n\tFor config -"
+ << configuration_.toString();
+
+ std::string prefix;
+ for (Resolution::Step step : steps) {
+ switch (step.type) {
+ case Resolution::Step::Type::INITIAL:
+ prefix = "Found initial";
+ break;
+ case Resolution::Step::Type::BETTER_MATCH:
+ prefix = "Found better";
+ break;
+ case Resolution::Step::Type::OVERLAID:
+ prefix = "Overlaid";
+ break;
+ }
+
+ if (!prefix.empty()) {
+ log_stream << "\n\t" << prefix << ": " << *step.package_name;
+
+ if (!step.config_name.isEmpty()) {
+ log_stream << " -" << step.config_name;
+ }
+ }
+ }
+
+ return log_stream.str();
+}
+
bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
FindEntryResult entry;
ApkAssetsCookie cookie =
@@ -495,27 +613,10 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons
return false;
}
- out_name->package = package->GetPackageName().data();
- out_name->package_len = package->GetPackageName().size();
-
- out_name->type = entry.type_string_ref.string8(&out_name->type_len);
- out_name->type16 = nullptr;
- if (out_name->type == nullptr) {
- out_name->type16 = entry.type_string_ref.string16(&out_name->type_len);
- if (out_name->type16 == nullptr) {
- return false;
- }
- }
-
- out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len);
- out_name->entry16 = nullptr;
- if (out_name->entry == nullptr) {
- out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len);
- if (out_name->entry16 == nullptr) {
- return false;
- }
- }
- return true;
+ return ToResourceName(entry.type_string_ref,
+ entry.entry_string_ref,
+ package,
+ out_name);
}
bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index 57e3491895e6..3dc1f2cd56c5 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -51,7 +51,7 @@ class XmlAttributeFinder
class BagAttributeFinder
: public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
public:
- BagAttributeFinder(const ResolvedBag* bag)
+ explicit BagAttributeFinder(const ResolvedBag* bag)
: BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
}
diff --git a/libs/androidfw/CursorWindow.cpp b/libs/androidfw/CursorWindow.cpp
index 5694115f61aa..a99e77f8dbb9 100644
--- a/libs/androidfw/CursorWindow.cpp
+++ b/libs/androidfw/CursorWindow.cpp
@@ -94,7 +94,7 @@ status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursor
if (size < 0) {
result = UNKNOWN_ERROR;
} else {
- int dupAshmemFd = ::dup(ashmemFd);
+ int dupAshmemFd = ::fcntl(ashmemFd, F_DUPFD_CLOEXEC, 0);
if (dupAshmemFd < 0) {
result = -errno;
} else {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 5a267804ddf1..70ce9bc705ef 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -593,7 +593,12 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
return {};
}
- // Iterate over the overlayable policy chunks
+ std::string name;
+ util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+ std::string actor;
+ util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+
+ // Iterate over the overlayable policy chunks contained within the overlayable chunk data
ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
while (overlayable_iter.HasNext()) {
const Chunk overlayable_child_chunk = overlayable_iter.Next();
@@ -613,7 +618,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
return {};
}
- // Retrieve all the ids belonging to this policy
+ // Retrieve all the resource ids belonging to this policy chunk
std::unordered_set<uint32_t> ids;
const auto ids_begin =
reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
@@ -622,8 +627,10 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
ids.insert(dtohl(id_iter->ident));
}
- // Add the pairing of overlayable properties to resource ids to the package
+ // Add the pairing of overlayable properties and resource ids to the package
OverlayableInfo overlayable_info{};
+ overlayable_info.name = name;
+ overlayable_info.actor = actor;
overlayable_info.policy_flags = policy_header->policy_flags;
loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
break;
@@ -636,7 +643,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
}
if (overlayable_iter.HadError()) {
- LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s",
+ LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s",
overlayable_iter.GetLastError().c_str());
if (overlayable_iter.HadFatalError()) {
return {};
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index d63feb01ef83..645984d85c34 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -48,4 +48,65 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin
!(has_type_separator && out_type->empty());
}
+bool ToResourceName(StringPoolRef& type_string_ref,
+ StringPoolRef& entry_string_ref,
+ const LoadedPackage* package,
+ AssetManager2::ResourceName* out_name) {
+ out_name->package = package->GetPackageName().data();
+ out_name->package_len = package->GetPackageName().size();
+
+ out_name->type = type_string_ref.string8(&out_name->type_len);
+ out_name->type16 = nullptr;
+ if (out_name->type == nullptr) {
+ out_name->type16 = type_string_ref.string16(&out_name->type_len);
+ if (out_name->type16 == nullptr) {
+ return false;
+ }
+ }
+
+ out_name->entry = entry_string_ref.string8(&out_name->entry_len);
+ out_name->entry16 = nullptr;
+ if (out_name->entry == nullptr) {
+ out_name->entry16 = entry_string_ref.string16(&out_name->entry_len);
+ if (out_name->entry16 == nullptr) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) {
+ std::string result;
+ if (resource_name->package != nullptr) {
+ result.append(resource_name->package, resource_name->package_len);
+ }
+
+ if (resource_name->type != nullptr || resource_name->type16 != nullptr) {
+ if (!result.empty()) {
+ result += ":";
+ }
+
+ if (resource_name->type != nullptr) {
+ result.append(resource_name->type, resource_name->type_len);
+ } else {
+ result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len));
+ }
+ }
+
+ if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) {
+ if (!result.empty()) {
+ result += "/";
+ }
+
+ if (resource_name->entry != nullptr) {
+ result.append(resource_name->entry, resource_name->entry_len);
+ } else {
+ result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len));
+ }
+ }
+
+ return result;
+}
+
} // namespace android
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 5d243da2097c..5be2105fe404 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -37,7 +37,7 @@ using namespace android;
// TODO: This can go away once the only remaining usage in aapt goes away.
class FileReader : public zip_archive::Reader {
public:
- FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
+ explicit FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
}
bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
diff --git a/libs/androidfw/include/androidfw/AssetDir.h b/libs/androidfw/include/androidfw/AssetDir.h
index 7aef02dc4133..ce6e066d6a16 100644
--- a/libs/androidfw/include/androidfw/AssetDir.h
+++ b/libs/androidfw/include/androidfw/AssetDir.h
@@ -78,7 +78,7 @@ private:
class FileInfo {
public:
FileInfo(void) {}
- FileInfo(const String8& path) // useful for e.g. svect.indexOf
+ explicit FileInfo(const String8& path) // useful for e.g. svect.indexOf
: mFileName(path), mFileType(kFileTypeUnknown)
{}
~FileInfo(void) {}
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 0d492984d41d..f29769b834d1 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -229,6 +229,14 @@ class AssetManager2 {
ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
uint32_t* out_last_reference) const;
+ // Enables or disables resource resolution logging. Clears stored steps when
+ // disabled.
+ void SetResourceResolutionLoggingEnabled(bool enabled);
+
+ // Returns formatted log of last resource resolution path, or empty if no
+ // resource has been resolved yet.
+ std::string GetLastResourceResolution() const;
+
// Retrieves the best matching bag/map resource with ID `resid`.
// This method will resolve all parent references for this bag and merge keys with the child.
// To iterate over the keys, use the following idiom:
@@ -346,6 +354,48 @@ class AssetManager2 {
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+
+ // Whether or not to save resource resolution steps
+ bool resource_resolution_logging_enabled_ = false;
+
+ struct Resolution {
+
+ struct Step {
+
+ enum class Type {
+ INITIAL,
+ BETTER_MATCH,
+ OVERLAID
+ };
+
+ // Marks what kind of override this step was.
+ Type type;
+
+ // Built name of configuration for this step.
+ String8 config_name;
+
+ // Marks the package name of the better resource found in this step.
+ const std::string* package_name;
+ };
+
+ // Last resolved resource ID.
+ uint32_t resid;
+
+ // Last resolved resource result cookie.
+ ApkAssetsCookie cookie = kInvalidCookie;
+
+ // Last resolved resource type.
+ StringPoolRef type_string_ref;
+
+ // Last resolved resource entry.
+ StringPoolRef entry_string_ref;
+
+ // Steps taken to resolve last resource.
+ std::vector<Step> steps;
+ };
+
+ // Record of the last resolved resource's resolution path.
+ mutable Resolution last_resolution;
};
class Theme {
diff --git a/libs/androidfw/include/androidfw/BackupHelpers.h b/libs/androidfw/include/androidfw/BackupHelpers.h
index fc1ad4717c16..2da247b77c0a 100644
--- a/libs/androidfw/include/androidfw/BackupHelpers.h
+++ b/libs/androidfw/include/androidfw/BackupHelpers.h
@@ -67,7 +67,7 @@ struct FileRec {
class BackupDataWriter
{
public:
- BackupDataWriter(int fd);
+ explicit BackupDataWriter(int fd);
// does not close fd
~BackupDataWriter();
@@ -104,7 +104,7 @@ private:
class BackupDataReader
{
public:
- BackupDataReader(int fd);
+ explicit BackupDataReader(int fd);
// does not close fd
~BackupDataReader();
diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
index 29424c4462aa..6fa089aeb12c 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -82,7 +82,7 @@ struct ConfigDescription : public ResTable_config {
static void ApplyVersionForCompatibility(ConfigDescription* config);
ConfigDescription();
- ConfigDescription(const android::ResTable_config& o); // NOLINT(implicit)
+ ConfigDescription(const android::ResTable_config& o); // NOLINT(google-explicit-constructor)
ConfigDescription(const ConfigDescription& o);
ConfigDescription(ConfigDescription&& o) noexcept;
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index e1dfb9490c60..bf35aa3c15bb 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -22,7 +22,7 @@ namespace android {
class DisplayEventDispatcher : public LooperCallback {
public:
- DisplayEventDispatcher(const sp<Looper>& looper,
+ explicit DisplayEventDispatcher(const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
status_t initialize();
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 8c5c3b7d3858..be62f30617bf 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,8 @@ struct TypeSpec {
using TypeSpecPtr = util::unique_cptr<TypeSpec>;
struct OverlayableInfo {
+ std::string name;
+ std::string actor;
uint32_t policy_flags;
};
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index cf2d8fb3251c..6b9ebd3e8d12 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -693,7 +693,7 @@ class ResXMLTree;
class ResXMLParser
{
public:
- ResXMLParser(const ResXMLTree& tree);
+ explicit ResXMLParser(const ResXMLTree& tree);
enum event_code_t {
BAD_DOCUMENT = -1,
@@ -806,7 +806,7 @@ public:
* The tree stores a clone of the specified DynamicRefTable, so any changes to the original
* DynamicRefTable will not affect this tree after instantiation.
**/
- ResXMLTree(const DynamicRefTable* dynamicRefTable);
+ explicit ResXMLTree(const DynamicRefTable* dynamicRefTable);
ResXMLTree();
~ResXMLTree();
@@ -1611,6 +1611,12 @@ struct ResTable_lib_entry
struct ResTable_overlayable_header
{
struct ResChunk_header header;
+
+ // The name of the overlayable set of resources that overlays target.
+ uint16_t name[256];
+
+ // The component responsible for enabling and disabling overlays targeting this chunk.
+ uint16_t actor[256];
};
/**
@@ -1844,7 +1850,7 @@ public:
class Theme {
public:
- Theme(const ResTable& table);
+ explicit Theme(const ResTable& table);
~Theme();
inline const ResTable& getResTable() const { return mTable; }
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index d94779bf5225..eb6eb8e66175 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -17,6 +17,7 @@
#ifndef ANDROIDFW_RESOURCEUTILS_H
#define ANDROIDFW_RESOURCEUTILS_H
+#include "androidfw/AssetManager2.h"
#include "androidfw/StringPiece.h"
namespace android {
@@ -27,6 +28,17 @@ namespace android {
bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
StringPiece* out_entry);
+// Convert a type_string_ref, entry_string_ref, and package
+// to AssetManager2::ResourceName. Useful for getting
+// resource name without re-running AssetManager2::FindEntry searches.
+bool ToResourceName(StringPoolRef& type_string_ref,
+ StringPoolRef& entry_string_ref,
+ const LoadedPackage* package,
+ AssetManager2::ResourceName* out_name);
+
+// Formats a ResourceName to "package:type/entry_name".
+std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name);
+
inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
}
diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
index a33865f4d34f..921877dc4982 100644
--- a/libs/androidfw/include/androidfw/StringPiece.h
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -52,8 +52,8 @@ class BasicStringPiece {
BasicStringPiece();
BasicStringPiece(const BasicStringPiece<TChar>& str);
- BasicStringPiece(const std::basic_string<TChar>& str); // NOLINT(implicit)
- BasicStringPiece(const TChar* str); // NOLINT(implicit)
+ BasicStringPiece(const std::basic_string<TChar>& str); // NOLINT(google-explicit-constructor)
+ BasicStringPiece(const TChar* str); // NOLINT(google-explicit-constructor)
BasicStringPiece(const TChar* str, size_t len);
BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
diff --git a/libs/androidfw/include/androidfw/TypeWrappers.h b/libs/androidfw/include/androidfw/TypeWrappers.h
index 5cfe54e5759d..fb2fad619011 100644
--- a/libs/androidfw/include/androidfw/TypeWrappers.h
+++ b/libs/androidfw/include/androidfw/TypeWrappers.h
@@ -23,7 +23,7 @@
namespace android {
struct TypeVariant {
- TypeVariant(const ResTable_type* data);
+ explicit TypeVariant(const ResTable_type* data);
class iterator {
public:
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 10d088e02829..aa1466fde778 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -46,7 +46,7 @@ class unique_cptr {
using pointer = typename std::add_pointer<T>::type;
constexpr unique_cptr() : ptr_(nullptr) {}
- constexpr unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
+ constexpr explicit unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
explicit unique_cptr(pointer ptr) : ptr_(ptr) {}
unique_cptr(unique_cptr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 5449a54d08de..105dcd209bf7 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -586,4 +586,111 @@ TEST_F(AssetManager2Test, OpenDirFromManyApks) {
EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
}
+TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
+ ResTable_config desired_config;
+
+ AssetManager2 assetmanager;
+ assetmanager.SetConfiguration(desired_config);
+ assetmanager.SetApkAssets({basic_assets_.get()});
+ assetmanager.SetResourceResolutionLoggingEnabled(false);
+
+ Res_value value;
+ ResTable_config selected_config;
+ uint32_t flags;
+
+ ApkAssetsCookie cookie =
+ assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+ 0 /*density_override*/, &value, &selected_config, &flags);
+ ASSERT_NE(kInvalidCookie, cookie);
+
+ auto result = assetmanager.GetLastResourceResolution();
+ EXPECT_EQ("", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) {
+ ResTable_config desired_config;
+
+ AssetManager2 assetmanager;
+ assetmanager.SetConfiguration(desired_config);
+ assetmanager.SetApkAssets({basic_assets_.get()});
+
+ auto result = assetmanager.GetLastResourceResolution();
+ EXPECT_EQ("", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+ desired_config.language[0] = 'd';
+ desired_config.language[1] = 'e';
+
+ AssetManager2 assetmanager;
+ assetmanager.SetResourceResolutionLoggingEnabled(true);
+ assetmanager.SetConfiguration(desired_config);
+ assetmanager.SetApkAssets({basic_assets_.get()});
+
+ Res_value value;
+ ResTable_config selected_config;
+ uint32_t flags;
+
+ ApkAssetsCookie cookie =
+ assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+ 0 /*density_override*/, &value, &selected_config, &flags);
+ ASSERT_NE(kInvalidCookie, cookie);
+
+ auto result = assetmanager.GetLastResourceResolution();
+ EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+ desired_config.language[0] = 'd';
+ desired_config.language[1] = 'e';
+
+ AssetManager2 assetmanager;
+ assetmanager.SetResourceResolutionLoggingEnabled(true);
+ assetmanager.SetConfiguration(desired_config);
+ assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+
+ Res_value value = Res_value();
+ ResTable_config selected_config;
+ uint32_t flags;
+
+ ApkAssetsCookie cookie =
+ assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+ 0 /*density_override*/, &value, &selected_config, &flags);
+ ASSERT_NE(kInvalidCookie, cookie);
+
+ auto result = assetmanager.GetLastResourceResolution();
+ EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result);
+}
+
+TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
+ ResTable_config desired_config;
+ memset(&desired_config, 0, sizeof(desired_config));
+
+ AssetManager2 assetmanager;
+ assetmanager.SetResourceResolutionLoggingEnabled(true);
+ assetmanager.SetConfiguration(desired_config);
+ assetmanager.SetApkAssets({basic_assets_.get()});
+
+ Res_value value = Res_value();
+ ResTable_config selected_config;
+ uint32_t flags;
+
+ ApkAssetsCookie cookie =
+ assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+ 0 /*density_override*/, &value, &selected_config, &flags);
+ ASSERT_NE(kInvalidCookie, cookie);
+
+ auto resultEnabled = assetmanager.GetLastResourceResolution();
+ ASSERT_NE("", resultEnabled);
+
+ assetmanager.SetResourceResolutionLoggingEnabled(false);
+
+ auto resultDisabled = assetmanager.GetLastResourceResolution();
+ EXPECT_EQ("", resultDisabled);
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 22d587a7f5c4..2e386a083185 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -294,22 +294,30 @@ TEST(LoadedArscTest, LoadOverlayable) {
info = package->GetOverlayableInfo(overlayable::R::string::overlayable1);
ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+ EXPECT_THAT(info->actor, Eq("overlay://theme"));
EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable2);
ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+ EXPECT_THAT(info->actor, Eq("overlay://theme"));
EXPECT_THAT(info->policy_flags,
Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable3);
ASSERT_THAT(info, NotNull());
+ EXPECT_THAT(info->name, Eq("OverlayableResources2"));
+ EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
EXPECT_THAT(info->policy_flags,
Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
+ EXPECT_THAT(info->name, Eq("OverlayableResources1"));
+ EXPECT_THAT(info->actor, Eq("overlay://theme"));
ASSERT_THAT(info, NotNull());
EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC));
}
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 85ab4be7a2e5..863474794d00 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
index 11aa7354901d..dba7b08628f1 100644
--- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -15,7 +15,7 @@
-->
<resources>
-<overlayable>
+<overlayable name="OverlayableResources1" actor="overlay://theme">
<!-- Any overlay can overlay the value of @string/overlayable1 -->
<item type="string" name="overlayable1" />
@@ -31,9 +31,9 @@
</policy>
</overlayable>
-<overlayable>
+<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable">
<!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
- @string/overlayable3 -->
+ @string/overlayable3 -->
<policy type="product_services|vendor|product">
<item type="string" name="overlayable3" />
</policy>
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index ed167e57158e..56b1885de820 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -79,8 +79,7 @@ static void queryWideColorGamutPreference(SkColorSpace::Gamut* colorGamut,
switch (wcgDataspace) {
case ui::Dataspace::DISPLAY_P3:
*colorGamut = SkColorSpace::Gamut::kDCIP3_D65_Gamut;
- *colorSpace = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
- SkColorSpace::Gamut::kDCIP3_D65_Gamut);
+ *colorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3);
break;
case ui::Dataspace::V0_SCRGB:
*colorGamut = SkColorSpace::Gamut::kSRGB_Gamut;
diff --git a/libs/hwui/private/hwui/DrawVkInfo.h b/libs/hwui/private/hwui/DrawVkInfo.h
index b2351fc026de..fd824bd957fd 100644
--- a/libs/hwui/private/hwui/DrawVkInfo.h
+++ b/libs/hwui/private/hwui/DrawVkInfo.h
@@ -52,17 +52,8 @@ struct DrawVkInfo {
// Input: Format of the destination surface.
VkFormat format;
- // Input: Color space transfer params
- float g;
- float a;
- float b;
- float c;
- float d;
- float e;
- float f;
-
- // Input: Color space transformation from linear RGB to D50-adapted XYZ
- float colorSpaceTransform[9];
+ // Input: Color space
+ const SkColorSpace* colorSpaceInfo;
// Input: current clip rect
int clipLeft;
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index f3a764874e2b..f6178aff0c2e 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -44,8 +44,8 @@ TEST(SkiaCanvas, drawShadowLayer) {
}
TEST(SkiaCanvas, colorSpaceXform) {
- sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
- SkColorSpace::kAdobeRGB_Gamut);
+ sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB,
+ SkNamedGamut::kAdobeRGB);
SkImageInfo adobeInfo = SkImageInfo::Make(1, 1, kN32_SkColorType, kOpaque_SkAlphaType, adobe);
sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo);
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index dc347f615d98..4415a593f6ee 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -25,38 +25,6 @@
namespace android {
namespace uirenderer {
-static inline bool almostEqual(float a, float b) {
- return std::abs(a - b) < 1e-2f;
-}
-
-bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) {
- if (colorSpace == nullptr) return true;
- if (colorSpace->isSRGB()) return true;
-
- SkColorSpaceTransferFn transferFunction;
- if (colorSpace->isNumericalTransferFn(&transferFunction)) {
- // sRGB transfer function params:
- const float sRGBParamA = 1 / 1.055f;
- const float sRGBParamB = 0.055f / 1.055f;
- const float sRGBParamC = 1 / 12.92f;
- const float sRGBParamD = 0.04045f;
- const float sRGBParamE = 0.0f;
- const float sRGBParamF = 0.0f;
- const float sRGBParamG = 2.4f;
-
- // This comparison will catch Display P3
- return almostEqual(sRGBParamA, transferFunction.fA) &&
- almostEqual(sRGBParamB, transferFunction.fB) &&
- almostEqual(sRGBParamC, transferFunction.fC) &&
- almostEqual(sRGBParamD, transferFunction.fD) &&
- almostEqual(sRGBParamE, transferFunction.fE) &&
- almostEqual(sRGBParamF, transferFunction.fF) &&
- almostEqual(sRGBParamG, transferFunction.fG);
- }
-
- return false;
-}
-
android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
switch (colorType) {
case kRGBA_8888_SkColorType:
@@ -79,19 +47,19 @@ android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) {
sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
- SkColorSpace::Gamut gamut;
+ skcms_Matrix3x3 gamut;
switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
case HAL_DATASPACE_STANDARD_BT709:
- gamut = SkColorSpace::kSRGB_Gamut;
+ gamut = SkNamedGamut::kSRGB;
break;
case HAL_DATASPACE_STANDARD_BT2020:
- gamut = SkColorSpace::kRec2020_Gamut;
+ gamut = SkNamedGamut::kRec2020;
break;
case HAL_DATASPACE_STANDARD_DCI_P3:
- gamut = SkColorSpace::kDCIP3_D65_Gamut;
+ gamut = SkNamedGamut::kDCIP3;
break;
case HAL_DATASPACE_STANDARD_ADOBE_RGB:
- gamut = SkColorSpace::kAdobeRGB_Gamut;
+ gamut = SkNamedGamut::kAdobeRGB;
break;
case HAL_DATASPACE_STANDARD_UNSPECIFIED:
return nullptr;
@@ -109,9 +77,9 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
case HAL_DATASPACE_TRANSFER_LINEAR:
- return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
case HAL_DATASPACE_TRANSFER_SRGB:
- return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut);
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
case HAL_DATASPACE_TRANSFER_GAMMA2_2:
return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut);
case HAL_DATASPACE_TRANSFER_GAMMA2_6:
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 4473ce632b1b..388025207ed6 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -111,11 +111,6 @@ static constexpr float EOCF(float srgb) {
#endif
}
-// Returns whether the specified color space's transfer function can be
-// approximated with the native sRGB transfer function. This method
-// returns true for sRGB, gamma 2.2 and Display P3 for instance
-bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
-
android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType);
ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace);
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index f179bc3f9d3d..602cc3e6d0fd 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -48,6 +48,7 @@ public final class GnssMeasurement implements Parcelable {
private int mMultipathIndicator;
private double mSnrInDb;
private double mAutomaticGainControlLevelInDb;
+ private int mCodeType;
// The following enumerations must be in sync with the values declared in gps.h
@@ -58,6 +59,7 @@ public final class GnssMeasurement implements Parcelable {
private static final int HAS_CARRIER_PHASE = (1<<11);
private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+ private static final int HAS_CODE_TYPE = (1 << 14);
/**
* The status of the multipath indicator.
@@ -202,6 +204,104 @@ public final class GnssMeasurement implements Parcelable {
public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4);
/**
+ * GNSS measurement code type.
+ * @hide
+ */
+ @IntDef(prefix = { "CODE_TYPE_" }, value = {
+ CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L,
+ CODE_TYPE_M, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W, CODE_TYPE_X,
+ CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_CODELESS
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CodeType {}
+
+ /** The GNSS Measurement's code type is unknown. */
+ public static final int CODE_TYPE_UNKNOWN = -1;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GALILEO E1A, GALILEO E6A, IRNSS
+ * L5A, IRNSS SA.
+ */
+ public static final int CODE_TYPE_A = 0;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GALILEO E1B, GALILEO E6B, IRNSS
+ * L5B, IRNSS SB.
+ */
+ public static final int CODE_TYPE_B = 1;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1 C/A, GPS L2 C/A, GLONASS G1
+ * C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C.
+ */
+ public static final int CODE_TYPE_C = 2;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L5 I, GLONASS G3 I, GALILEO E5a
+ * I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I.
+ */
+ public static final int CODE_TYPE_I = 3;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1C (P), GPS L2C (L), QZSS L1C
+ * (P), QZSS L2C (L), LEX(6) L.
+ */
+ public static final int CODE_TYPE_L = 4;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1M, GPS L2M.
+ */
+ public static final int CODE_TYPE_M = 5;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1P, GPS L2P, GLONASS G1P,
+ * GLONASS G2P.
+ */
+ public static final int CODE_TYPE_P = 6;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L5 Q, GLONASS G3 Q, GALILEO E5a
+ * Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q.
+ */
+ public static final int CODE_TYPE_Q = 7;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1C (D), GPS L2C (M), QZSS L1C
+ * (D), QZSS L2C (M), LEX(6) S.
+ */
+ public static final int CODE_TYPE_S = 8;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1 Z-tracking, GPS L2
+ * Z-tracking.
+ */
+ public static final int CODE_TYPE_W = 9;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1C (D+P), GPS L2C (M+L), GPS
+ * L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO
+ * E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q),
+ * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C).
+ */
+ public static final int CODE_TYPE_X = 10;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1Y, GPS L2Y.
+ */
+ public static final int CODE_TYPE_Y = 11;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GALILEO E1 (A+B+C), GALILEO E6
+ * (A+B+C), QZSS L1-SAIF.
+ */
+ public static final int CODE_TYPE_Z = 12;
+
+ /**
+ * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless.
+ */
+ public static final int CODE_TYPE_CODELESS = 13;
+
+ /**
* All the 'Accumulated Delta Range' flags.
* @hide
*/
@@ -248,6 +348,7 @@ public final class GnssMeasurement implements Parcelable {
mMultipathIndicator = measurement.mMultipathIndicator;
mSnrInDb = measurement.mSnrInDb;
mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
+ mCodeType = measurement.mCodeType;
}
/**
@@ -967,7 +1068,7 @@ public final class GnssMeasurement implements Parcelable {
* <p>For internal and logging use only.
*/
private String getMultipathIndicatorString() {
- switch(mMultipathIndicator) {
+ switch (mMultipathIndicator) {
case MULTIPATH_INDICATOR_UNKNOWN:
return "Unknown";
case MULTIPATH_INDICATOR_DETECTED:
@@ -1063,6 +1164,89 @@ public final class GnssMeasurement implements Parcelable {
mAutomaticGainControlLevelInDb = Double.NaN;
}
+ /**
+ * Returns {@code true} if {@link #getCodeType()} is available,
+ * {@code false} otherwise.
+ */
+ public boolean hasCodeType() {
+ return isFlagSet(HAS_CODE_TYPE);
+ }
+
+ /**
+ * Gets the GNSS measurement's code type.
+ *
+ * <p>Similar to the Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table
+ * A2 at the Rinex 3.03 Update 1 Document.
+ */
+ @CodeType
+ public int getCodeType() {
+ return mCodeType;
+ }
+
+ /**
+ * Sets the GNSS measurement's code type.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setCodeType(@CodeType int codeType) {
+ setFlag(HAS_CODE_TYPE);
+ mCodeType = codeType;
+ }
+
+ /**
+ * Resets the GNSS measurement's code type.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetCodeType() {
+ resetFlag(HAS_CODE_TYPE);
+ mCodeType = CODE_TYPE_UNKNOWN;
+ }
+
+ /**
+ * Gets a string representation of the 'code type'.
+ *
+ * <p>For internal and logging use only.
+ */
+ private String getCodeTypeString() {
+ switch (mCodeType) {
+ case CODE_TYPE_UNKNOWN:
+ return "CODE_TYPE_UNKNOWN";
+ case CODE_TYPE_A:
+ return "CODE_TYPE_A";
+ case CODE_TYPE_B:
+ return "CODE_TYPE_B";
+ case CODE_TYPE_C:
+ return "CODE_TYPE_C";
+ case CODE_TYPE_I:
+ return "CODE_TYPE_I";
+ case CODE_TYPE_L:
+ return "CODE_TYPE_L";
+ case CODE_TYPE_M:
+ return "CODE_TYPE_M";
+ case CODE_TYPE_P:
+ return "CODE_TYPE_P";
+ case CODE_TYPE_Q:
+ return "CODE_TYPE_Q";
+ case CODE_TYPE_S:
+ return "CODE_TYPE_S";
+ case CODE_TYPE_W:
+ return "CODE_TYPE_W";
+ case CODE_TYPE_X:
+ return "CODE_TYPE_X";
+ case CODE_TYPE_Y:
+ return "CODE_TYPE_Y";
+ case CODE_TYPE_Z:
+ return "CODE_TYPE_Z";
+ case CODE_TYPE_CODELESS:
+ return "CODE_TYPE_CODELESS";
+ default:
+ return "<Invalid: " + mCodeType + ">";
+ }
+ }
+
public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
@Override
public GnssMeasurement createFromParcel(Parcel parcel) {
@@ -1088,6 +1272,7 @@ public final class GnssMeasurement implements Parcelable {
gnssMeasurement.mMultipathIndicator = parcel.readInt();
gnssMeasurement.mSnrInDb = parcel.readDouble();
gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
+ gnssMeasurement.mCodeType = parcel.readInt();
return gnssMeasurement;
}
@@ -1120,6 +1305,7 @@ public final class GnssMeasurement implements Parcelable {
parcel.writeInt(mMultipathIndicator);
parcel.writeDouble(mSnrInDb);
parcel.writeDouble(mAutomaticGainControlLevelInDb);
+ parcel.writeInt(mCodeType);
}
@Override
@@ -1191,9 +1377,13 @@ public final class GnssMeasurement implements Parcelable {
"SnrInDb",
hasSnrInDb() ? mSnrInDb : null));
builder.append(String.format(
- format,
- "AgcLevelDb",
- hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+ format,
+ "AgcLevelDb",
+ hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null));
+ builder.append(String.format(
+ format,
+ "CodeType",
+ hasCodeType() ? getCodeTypeString() : null));
return builder.toString();
}
@@ -1218,6 +1408,7 @@ public final class GnssMeasurement implements Parcelable {
setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
resetSnrInDb();
resetAutomaticGainControlLevel();
+ resetCodeType();
}
private void setFlag(int flag) {
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0375de3cc496..bc9500ddb3b7 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -2289,6 +2289,30 @@ final public class MediaCodec {
*/
public static final int ERROR_UNSUPPORTED_OPERATION = 6;
+ /**
+ * This indicates that the security level of the device is not
+ * sufficient to meet the requirements set by the content owner
+ * in the license policy.
+ */
+ public static final int ERROR_INSUFFICIENT_SECURITY = 7;
+
+ /**
+ * This indicates that the video frame being decrypted exceeds
+ * the size of the device's protected output buffers. When
+ * encountering this error the app should try playing content
+ * of a lower resolution.
+ */
+ public static final int ERROR_FRAME_TOO_LARGE = 8;
+
+ /**
+ * This error indicates that session state has been
+ * invalidated. It can occur on devices that are not capable
+ * of retaining crypto session state across device
+ * suspend/resume. The session must be closed and a new
+ * session opened to resume operation.
+ */
+ public static final int ERROR_LOST_STATE = 9;
+
/** @hide */
@IntDef({
ERROR_NO_KEY,
@@ -2296,7 +2320,10 @@ final public class MediaCodec {
ERROR_RESOURCE_BUSY,
ERROR_INSUFFICIENT_OUTPUT_PROTECTION,
ERROR_SESSION_NOT_OPENED,
- ERROR_UNSUPPORTED_OPERATION
+ ERROR_UNSUPPORTED_OPERATION,
+ ERROR_INSUFFICIENT_SECURITY,
+ ERROR_FRAME_TOO_LARGE,
+ ERROR_LOST_STATE
})
@Retention(RetentionPolicy.SOURCE)
public @interface CryptoErrorCode {}
diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java
index 275b0acd8ad6..5a5747ae4bab 100644
--- a/media/java/android/media/MediaConstants.java
+++ b/media/java/android/media/MediaConstants.java
@@ -24,7 +24,7 @@ class MediaConstants {
static final String KEY_PACKAGE_NAME = "android.media.key.PACKAGE_NAME";
// Bundle key for Parcelable
- static final String KEY_SESSION2_STUB = "android.media.key.SESSION2_STUB";
+ static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK";
static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS";
private MediaConstants() {
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index b8381a7249be..774ea185f57c 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -19,7 +19,7 @@ package android.media;
import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
import static android.media.MediaConstants.KEY_PACKAGE_NAME;
import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.MediaConstants.KEY_SESSION2LINK;
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
import static android.media.Session2Token.TYPE_SESSION;
@@ -41,15 +41,15 @@ import java.util.concurrent.Executor;
/**
* Allows an app to interact with an active {@link MediaSession2} or a
- * {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
+ * MediaSession2Service which would provide {@link MediaSession2}. Media buttons and other
* commands can be sent to the session.
* <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
* for consistent behavior across all devices.
- * @hide
*/
+// TODO: use @link for MediaSession2Service
public class MediaController2 implements AutoCloseable {
static final String TAG = "MediaController2";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -130,8 +130,8 @@ public class MediaController2 implements AutoCloseable {
synchronized (mLock) {
if (mSessionBinder != null) {
try {
- mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
mSessionBinder.disconnect(mControllerStub, getNextSeqNumber());
+ mSessionBinder.unlinkToDeath(mDeathRecipient, 0);
} catch (RuntimeException e) {
// No-op
}
@@ -153,6 +153,7 @@ public class MediaController2 implements AutoCloseable {
* @return a token which will be sent together in {@link ControllerCallback#onCommandResult}
* when its result is received.
*/
+ @NonNull
public Object sendSessionCommand(@NonNull Session2Command command, @Nullable Bundle args) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
@@ -208,7 +209,7 @@ public class MediaController2 implements AutoCloseable {
void onConnected(int seq, Bundle connectionResult) {
final long token = Binder.clearCallingIdentity();
try {
- Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2_STUB);
+ Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK);
Session2CommandGroup allowedCommands =
connectionResult.getParcelable(KEY_ALLOWED_COMMANDS);
if (DEBUG) {
@@ -349,7 +350,7 @@ public class MediaController2 implements AutoCloseable {
* @return the result for the session command. A runtime exception will be thrown if null
* is returned.
*/
- @NonNull
+ @Nullable
public Session2Command.Result onSessionCommand(@NonNull MediaController2 controller,
@NonNull Session2Command command, @Nullable Bundle args) {
return null;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index cdbc7b44f905..75b391534dd4 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -132,11 +132,19 @@ public final class MediaDrm implements AutoCloseable {
private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
private EventHandler mEventHandler;
- private EventHandler mOnKeyStatusChangeEventHandler;
- private EventHandler mOnExpirationUpdateEventHandler;
+ private EventHandler mKeyStatusChangeHandler;
+ private EventHandler mExpirationUpdateHandler;
+ private EventHandler mSessionLostStateHandler;
+
private OnEventListener mOnEventListener;
private OnKeyStatusChangeListener mOnKeyStatusChangeListener;
private OnExpirationUpdateListener mOnExpirationUpdateListener;
+ private OnSessionLostStateListener mOnSessionLostStateListener;
+
+ private final Object mEventLock = new Object();
+ private final Object mKeyStatusChangeLock = new Object();
+ private final Object mExpirationUpdateLock = new Object();
+ private final Object mSessionLostStateLock = new Object();
private long mNativeContext;
@@ -200,6 +208,35 @@ public final class MediaDrm implements AutoCloseable {
private static final native boolean isCryptoSchemeSupportedNative(
@NonNull byte[] uuid, @Nullable String mimeType);
+ private EventHandler createHandler() {
+ Looper looper;
+ EventHandler handler;
+ if ((looper = Looper.myLooper()) != null) {
+ handler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ handler = new EventHandler(this, looper);
+ } else {
+ handler = null;
+ }
+ return handler;
+ }
+
+ private EventHandler updateHandler(Handler handler) {
+ Looper looper;
+ EventHandler newHandler = null;
+ if (handler != null) {
+ looper = handler.getLooper();
+ } else {
+ looper = Looper.myLooper();
+ }
+ if (looper != null) {
+ if (handler == null || handler.getLooper() != looper) {
+ newHandler = new EventHandler(this, looper);
+ }
+ }
+ return newHandler;
+ }
+
/**
* Instantiate a MediaDrm object
*
@@ -209,14 +246,10 @@ public final class MediaDrm implements AutoCloseable {
* specified scheme UUID
*/
public MediaDrm(@NonNull UUID uuid) throws UnsupportedSchemeException {
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(this, looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mEventHandler = new EventHandler(this, looper);
- } else {
- mEventHandler = null;
- }
+ mEventHandler = createHandler();
+ mKeyStatusChangeHandler = createHandler();
+ mExpirationUpdateHandler = createHandler();
+ mSessionLostStateHandler = createHandler();
/* Native setup requires a weak reference to our object.
* It's easier to create it here than in C++.
@@ -272,6 +305,40 @@ public final class MediaDrm implements AutoCloseable {
}
/**
+ * Thrown when an error occurs in any method that has a session context.
+ */
+ public static final class SessionException extends RuntimeException {
+ public SessionException(int errorCode, @Nullable String detailMessage) {
+ super(detailMessage);
+ mErrorCode = errorCode;
+ }
+
+ /**
+ * This indicates that apps using MediaDrm sessions are
+ * temporarily exceeding the capacity of available crypto
+ * resources. The app should retry the operation later.
+ */
+ public static final int ERROR_RESOURCE_CONTENTION = 1;
+
+ /** @hide */
+ @IntDef({
+ ERROR_RESOURCE_CONTENTION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SessionErrorCode {}
+
+ /**
+ * Retrieve the error code associated with the SessionException
+ */
+ @SessionErrorCode
+ public int getErrorCode() {
+ return mErrorCode;
+ }
+
+ private final int mErrorCode;
+ }
+
+ /**
* Register a callback to be invoked when a session expiration update
* occurs. The app's OnExpirationUpdateListener will be notified
* when the expiration time of the keys in the session have changed.
@@ -282,15 +349,12 @@ public final class MediaDrm implements AutoCloseable {
*/
public void setOnExpirationUpdateListener(
@Nullable OnExpirationUpdateListener listener, @Nullable Handler handler) {
- if (listener != null) {
- Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
- if (looper != null) {
- if (mEventHandler == null || mEventHandler.getLooper() != looper) {
- mEventHandler = new EventHandler(this, looper);
- }
+ synchronized(mExpirationUpdateLock) {
+ if (listener != null) {
+ mExpirationUpdateHandler = updateHandler(handler);
}
+ mOnExpirationUpdateListener = listener;
}
- mOnExpirationUpdateListener = listener;
}
/**
@@ -324,15 +388,12 @@ public final class MediaDrm implements AutoCloseable {
*/
public void setOnKeyStatusChangeListener(
@Nullable OnKeyStatusChangeListener listener, @Nullable Handler handler) {
- if (listener != null) {
- Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
- if (looper != null) {
- if (mEventHandler == null || mEventHandler.getLooper() != looper) {
- mEventHandler = new EventHandler(this, looper);
- }
+ synchronized(mKeyStatusChangeLock) {
+ if (listener != null) {
+ mKeyStatusChangeHandler = updateHandler(handler);
}
+ mOnKeyStatusChangeListener = listener;
}
- mOnKeyStatusChangeListener = listener;
}
/**
@@ -360,6 +421,46 @@ public final class MediaDrm implements AutoCloseable {
}
/**
+ * Register a callback to be invoked when session state has been
+ * lost. This event can occur on devices that are not capable of
+ * retaining crypto session state across device suspend/resume
+ * cycles. When this event occurs, the session must be closed and
+ * a new session opened to resume operation.
+ *
+ * @param listener the callback that will be run, or {@code null} to unregister the
+ * previously registered callback.
+ * @param handler the handler on which the listener should be invoked, or
+ * {@code null} if the listener should be invoked on the calling thread's looper.
+ */
+ public void setOnSessionLostStateListener(
+ @Nullable OnSessionLostStateListener listener, @Nullable Handler handler) {
+ synchronized(mSessionLostStateLock) {
+ if (listener != null) {
+ mSessionLostStateHandler = updateHandler(handler);
+ }
+ mOnSessionLostStateListener = listener;
+ }
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the
+ * session state has been lost and is now invalid
+ */
+ public interface OnSessionLostStateListener
+ {
+ /**
+ * Called when session state has lost state, to inform the app
+ * about the condition so it can close the session and open a new
+ * one to resume operation.
+ *
+ * @param md the MediaDrm object on which the event occurred
+ * @param sessionId the DRM session ID on which the event occurred
+ */
+ void onSessionLostState(
+ @NonNull MediaDrm md, @NonNull byte[] sessionId);
+ }
+
+ /**
* Defines the status of a key.
* A KeyStatus for each key in a session is provided to the
* {@link OnKeyStatusChangeListener#onKeyStatusChange}
@@ -437,7 +538,9 @@ public final class MediaDrm implements AutoCloseable {
*/
public void setOnEventListener(@Nullable OnEventListener listener)
{
- mOnEventListener = listener;
+ synchronized(mEventLock) {
+ mOnEventListener = listener;
+ }
}
/**
@@ -513,6 +616,7 @@ public final class MediaDrm implements AutoCloseable {
private static final int DRM_EVENT = 200;
private static final int EXPIRATION_UPDATE = 201;
private static final int KEY_STATUS_CHANGE = 202;
+ private static final int SESSION_LOST_STATE = 203;
private class EventHandler extends Handler
{
@@ -532,52 +636,72 @@ public final class MediaDrm implements AutoCloseable {
switch(msg.what) {
case DRM_EVENT:
- if (mOnEventListener != null) {
- if (msg.obj != null && msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel)msg.obj;
- byte[] sessionId = parcel.createByteArray();
- if (sessionId.length == 0) {
- sessionId = null;
- }
- byte[] data = parcel.createByteArray();
- if (data.length == 0) {
- data = null;
+ synchronized(mEventLock) {
+ if (mOnEventListener != null) {
+ if (msg.obj != null && msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ byte[] sessionId = parcel.createByteArray();
+ if (sessionId.length == 0) {
+ sessionId = null;
+ }
+ byte[] data = parcel.createByteArray();
+ if (data.length == 0) {
+ data = null;
+ }
+
+ Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
+ mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
}
-
- Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
- mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
}
}
return;
case KEY_STATUS_CHANGE:
- if (mOnKeyStatusChangeListener != null) {
- if (msg.obj != null && msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel)msg.obj;
- byte[] sessionId = parcel.createByteArray();
- if (sessionId.length > 0) {
- List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
- boolean hasNewUsableKey = (parcel.readInt() != 0);
-
- Log.i(TAG, "Drm key status changed");
- mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
- keyStatusList, hasNewUsableKey);
+ synchronized(mKeyStatusChangeLock) {
+ if (mOnKeyStatusChangeListener != null) {
+ if (msg.obj != null && msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ byte[] sessionId = parcel.createByteArray();
+ if (sessionId.length > 0) {
+ List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
+ boolean hasNewUsableKey = (parcel.readInt() != 0);
+
+ Log.i(TAG, "Drm key status changed");
+ mOnKeyStatusChangeListener.onKeyStatusChange(mMediaDrm, sessionId,
+ keyStatusList, hasNewUsableKey);
+ }
}
}
}
return;
case EXPIRATION_UPDATE:
- if (mOnExpirationUpdateListener != null) {
- if (msg.obj != null && msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel)msg.obj;
- byte[] sessionId = parcel.createByteArray();
- if (sessionId.length > 0) {
- long expirationTime = parcel.readLong();
-
- Log.i(TAG, "Drm key expiration update: " + expirationTime);
- mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
- expirationTime);
+ synchronized(mExpirationUpdateLock) {
+ if (mOnExpirationUpdateListener != null) {
+ if (msg.obj != null && msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ byte[] sessionId = parcel.createByteArray();
+ if (sessionId.length > 0) {
+ long expirationTime = parcel.readLong();
+
+ Log.i(TAG, "Drm key expiration update: " + expirationTime);
+ mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
+ expirationTime);
+ }
+ }
+ }
+ }
+ return;
+
+ case SESSION_LOST_STATE:
+ synchronized(mSessionLostStateLock) {
+ if (mOnSessionLostStateListener != null) {
+ if (msg.obj != null && msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ byte[] sessionId = parcel.createByteArray();
+ Log.i(TAG, "Drm session lost state event: ");
+ mOnSessionLostStateListener.onSessionLostState(mMediaDrm,
+ sessionId);
}
}
}
@@ -619,9 +743,42 @@ public final class MediaDrm implements AutoCloseable {
if (md == null) {
return;
}
- if (md.mEventHandler != null) {
- Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
- md.mEventHandler.sendMessage(m);
+ switch (what) {
+ case DRM_EVENT:
+ synchronized(md.mEventLock) {
+ if (md.mEventHandler != null) {
+ Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
+ md.mEventHandler.sendMessage(m);
+ }
+ }
+ break;
+ case EXPIRATION_UPDATE:
+ synchronized(md.mExpirationUpdateLock) {
+ if (md.mExpirationUpdateHandler != null) {
+ Message m = md.mExpirationUpdateHandler.obtainMessage(what, obj);
+ md.mExpirationUpdateHandler.sendMessage(m);
+ }
+ }
+ break;
+ case KEY_STATUS_CHANGE:
+ synchronized(md.mKeyStatusChangeLock) {
+ if (md.mKeyStatusChangeHandler != null) {
+ Message m = md.mKeyStatusChangeHandler.obtainMessage(what, obj);
+ md.mKeyStatusChangeHandler.sendMessage(m);
+ }
+ }
+ break;
+ case SESSION_LOST_STATE:
+ synchronized(md.mSessionLostStateLock) {
+ if (md.mSessionLostStateHandler != null) {
+ Message m = md.mSessionLostStateHandler.obtainMessage(what, obj);
+ md.mSessionLostStateHandler.sendMessage(m);
+ }
+ }
+ break;
+ default:
+ Log.e(TAG, "Unknown message type " + what);
+ break;
}
}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 7b20f7ae5954..e008adf120ab 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -19,7 +19,7 @@ package android.media;
import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS;
import static android.media.MediaConstants.KEY_PACKAGE_NAME;
import static android.media.MediaConstants.KEY_PID;
-import static android.media.MediaConstants.KEY_SESSION2_STUB;
+import static android.media.MediaConstants.KEY_SESSION2LINK;
import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR;
import static android.media.Session2Command.RESULT_INFO_SKIPPED;
import static android.media.Session2Token.TYPE_SESSION;
@@ -56,10 +56,9 @@ import java.util.concurrent.Executor;
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
* for consistent behavior across all devices.
- * @hide
*/
public class MediaSession2 implements AutoCloseable {
- static final String TAG = "MediaSession";
+ static final String TAG = "MediaSession2";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
// Note: This checks the uniqueness of a session ID only in a single process.
@@ -89,7 +88,6 @@ public class MediaSession2 implements AutoCloseable {
private final Handler mResultHandler;
//@GuardedBy("mLock")
- @SuppressWarnings("WeakerAccess") /* synthetic access */
private boolean mClosed;
MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity,
@@ -113,6 +111,7 @@ public class MediaSession2 implements AutoCloseable {
Context.MEDIA_SESSION_SERVICE);
// NOTE: mResultHandler uses main looper, so this MUST NOT be blocked.
mResultHandler = new Handler(context.getMainLooper());
+ mClosed = false;
}
@Override
@@ -179,6 +178,7 @@ public class MediaSession2 implements AutoCloseable {
* @return a token which will be sent together in {@link SessionCallback#onCommandResult}
* when its result is received.
*/
+ @NonNull
public Object sendSessionCommand(@NonNull ControllerInfo controller,
@NonNull Session2Command command, @Nullable Bundle args) {
if (controller == null) {
@@ -206,7 +206,10 @@ public class MediaSession2 implements AutoCloseable {
* @param controller the controller to get the session command
* @param token the token which is returned from {@link #sendSessionCommand}.
*/
- public void cancelSessionCommand(ControllerInfo controller, Object token) {
+ public void cancelSessionCommand(@NonNull ControllerInfo controller, @NonNull Object token) {
+ if (controller == null) {
+ throw new IllegalArgumentException("controller shouldn't be null");
+ }
if (token == null) {
throw new IllegalArgumentException("token shouldn't be null");
}
@@ -267,7 +270,7 @@ public class MediaSession2 implements AutoCloseable {
// It's needed because we cannot call synchronous calls between
// session/controller.
Bundle connectionResult = new Bundle();
- connectionResult.putParcelable(KEY_SESSION2_STUB, mSessionStub);
+ connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub);
connectionResult.putParcelable(KEY_ALLOWED_COMMANDS,
controllerInfo.mAllowedCommands);
@@ -558,7 +561,7 @@ public class MediaSession2 implements AutoCloseable {
}
@Override
- public boolean equals(Object obj) {
+ public boolean equals(@Nullable Object obj) {
if (!(obj instanceof ControllerInfo)) return false;
if (this == obj) return true;
@@ -570,6 +573,7 @@ public class MediaSession2 implements AutoCloseable {
}
@Override
+ @NonNull
public String toString() {
return "ControllerInfo {pkg=" + mRemoteUserInfo.getPackageName() + ", uid="
+ mRemoteUserInfo.getUid() + ", allowedCommands=" + mAllowedCommands + "})";
@@ -693,7 +697,7 @@ public class MediaSession2 implements AutoCloseable {
* @return the result for the session command. A runtime exception will be thrown if null
* is returned.
*/
- @NonNull
+ @Nullable
public Session2Command.Result onSessionCommand(@NonNull MediaSession2 session,
@NonNull ControllerInfo controller, @NonNull Session2Command command,
@Nullable Bundle args) {
diff --git a/media/java/android/media/Session2CommandGroup.java b/media/java/android/media/Session2CommandGroup.java
index 519888e86462..a189c264b029 100644
--- a/media/java/android/media/Session2CommandGroup.java
+++ b/media/java/android/media/Session2CommandGroup.java
@@ -59,6 +59,7 @@ public final class Session2CommandGroup implements Parcelable {
*
* @param commands The collection of commands to copy.
*/
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
Session2CommandGroup(@Nullable Collection<Session2Command> commands) {
if (commands != null) {
mCommands.addAll(commands);
diff --git a/media/java/android/media/Session2Token.java b/media/java/android/media/Session2Token.java
index e1fff38c6a79..95ee4c039f4b 100644
--- a/media/java/android/media/Session2Token.java
+++ b/media/java/android/media/Session2Token.java
@@ -34,7 +34,7 @@ import java.util.List;
import java.util.Objects;
/**
- * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
+ * Represents an ongoing {@link MediaSession2} or a MediaSession2Service.
* If it's representing a session service, it may not be ongoing.
* <p>
* This API is not generally intended for third party application developers.
@@ -45,9 +45,8 @@ import java.util.Objects;
* This may be passed to apps by the session owner to allow them to create a
* {@link MediaController2} to communicate with the session.
* <p>
- * It can be also obtained by {@link MediaSessionManager}.
+ * It can be also obtained by {@link android.media.session.MediaSessionManager}.
*
- * @hide
*/
// New version of MediaSession2.Token for following reasons
// - Stop implementing Parcelable for updatable support
@@ -56,6 +55,7 @@ import java.util.Objects;
// This helps controller apps to keep target of dispatching media key events in uniform way.
// For details about the reason, see following. (Android O+)
// android.media.session.MediaSessionManager.Callback#onAddressedPlayerChanged
+// TODO: use @link for MediaSession2Service
public final class Session2Token implements Parcelable {
private static final String TAG = "Session2Token";
@@ -75,7 +75,7 @@ public final class Session2Token implements Parcelable {
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
+ @IntDef(prefix = "TYPE_", value = {TYPE_SESSION, TYPE_SESSION_SERVICE})
public @interface TokenType {
}
@@ -85,15 +85,10 @@ public final class Session2Token implements Parcelable {
public static final int TYPE_SESSION = 0;
/**
- * Type for {@link MediaSession2Service}.
+ * Type for MediaSession2Service.
*/
public static final int TYPE_SESSION_SERVICE = 1;
- /**
- * Type for {@link MediaLibrary2Service}.
- */
- public static final int TYPE_LIBRARY_SERVICE = 2;
-
private final int mUid;
private final @TokenType int mType;
private final String mPackageName;
@@ -102,8 +97,7 @@ public final class Session2Token implements Parcelable {
private final ComponentName mComponentName;
/**
- * Constructor for the token with type {@link #TYPE_SESSION_SERVICE} or
- * {@link #TYPE_LIBRARY_SERVICE}.
+ * Constructor for the token with type {@link #TYPE_SESSION_SERVICE}.
*
* @param context The context.
* @param serviceComponent The component name of the service.
@@ -239,7 +233,6 @@ public final class Session2Token implements Parcelable {
* @return type of the token
* @see #TYPE_SESSION
* @see #TYPE_SESSION_SERVICE
- * @see #TYPE_LIBRARY_SERVICE
*/
public @TokenType int getType() {
return mType;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index d6b6339b8f5f..452c6e1becca 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -34,7 +34,6 @@ cc_library_shared {
"libutils",
"libbinder",
"libmedia",
- "libmediaextractor",
"libmedia_omx",
"libmediametrics",
"libmediadrm",
@@ -125,12 +124,12 @@ cc_library_shared {
"libcutils",
"libmedia_helper",
"libmedia_player2_util",
- "libmediaextractor",
"libmediaplayer2",
"libmediaplayer2-protos",
"libmediandk_utils",
"libmediautils",
"libprotobuf-cpp-lite",
+ "libstagefright",
"libstagefright_esds",
"libstagefright_foundation",
"libstagefright_httplive",
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 257860890437..7b07bea3cf1a 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -72,7 +72,10 @@ static struct CryptoErrorCodes {
jint cryptoErrorResourceBusy;
jint cryptoErrorInsufficientOutputProtection;
jint cryptoErrorSessionNotOpened;
+ jint cryptoErrorInsufficientSecurity;
jint cryptoErrorUnsupportedOperation;
+ jint cryptoErrorFrameTooLarge;
+ jint cryptoErrorLostState;
} gCryptoErrorCodes;
static struct CodecActionCodes {
@@ -1005,10 +1008,22 @@ static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
err = gCryptoErrorCodes.cryptoErrorSessionNotOpened;
defaultMsg = "Attempted to use a closed session";
break;
+ case ERROR_DRM_INSUFFICIENT_SECURITY:
+ err = gCryptoErrorCodes.cryptoErrorInsufficientSecurity;
+ defaultMsg = "Required security level is not met";
+ break;
case ERROR_DRM_CANNOT_HANDLE:
err = gCryptoErrorCodes.cryptoErrorUnsupportedOperation;
defaultMsg = "Operation not supported in this configuration";
break;
+ case ERROR_DRM_FRAME_TOO_LARGE:
+ err = gCryptoErrorCodes.cryptoErrorFrameTooLarge;
+ defaultMsg = "Decrytped frame exceeds size of output buffer";
+ break;
+ case ERROR_DRM_SESSION_LOST_STATE:
+ err = gCryptoErrorCodes.cryptoErrorLostState;
+ defaultMsg = "Session state was lost, open a new session and retry";
+ break;
default: /* Other negative DRM error codes go out as is. */
break;
}
@@ -1994,11 +2009,26 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) {
gCryptoErrorCodes.cryptoErrorSessionNotOpened =
env->GetStaticIntField(clazz.get(), field);
+ field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_SECURITY", "I");
+ CHECK(field != NULL);
+ gCryptoErrorCodes.cryptoErrorInsufficientSecurity =
+ env->GetStaticIntField(clazz.get(), field);
+
field = env->GetStaticFieldID(clazz.get(), "ERROR_UNSUPPORTED_OPERATION", "I");
CHECK(field != NULL);
gCryptoErrorCodes.cryptoErrorUnsupportedOperation =
env->GetStaticIntField(clazz.get(), field);
+ field = env->GetStaticFieldID(clazz.get(), "ERROR_FRAME_TOO_LARGE", "I");
+ CHECK(field != NULL);
+ gCryptoErrorCodes.cryptoErrorFrameTooLarge =
+ env->GetStaticIntField(clazz.get(), field);
+
+ field = env->GetStaticFieldID(clazz.get(), "ERROR_LOST_STATE", "I");
+ CHECK(field != NULL);
+ gCryptoErrorCodes.cryptoErrorLostState =
+ env->GetStaticIntField(clazz.get(), field);
+
clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
CHECK(clazz.get() != NULL);
field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index be71dad571bb..83364590039d 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -110,6 +110,7 @@ struct EventWhat {
jint kWhatDrmEvent;
jint kWhatExpirationUpdate;
jint kWhatKeyStatusChange;
+ jint kWhatSessionLostState;
} gEventWhat;
struct KeyTypes {
@@ -141,6 +142,16 @@ struct StateExceptionFields {
jclass classId;
};
+struct SessionExceptionFields {
+ jmethodID init;
+ jclass classId;
+ jfieldID errorCode;
+};
+
+struct SessionExceptionErrorCodes {
+ jint kResourceContention;
+} gSessionExceptionErrorCodes;
+
struct HDCPLevels {
jint kHdcpLevelUnknown;
jint kHdcpNone;
@@ -180,6 +191,7 @@ struct fields_t {
EntryFields entry;
CertificateFields certificate;
StateExceptionFields stateException;
+ SessionExceptionFields sessionException;
jclass certificateClassId;
jclass hashmapClassId;
jclass arraylistClassId;
@@ -310,6 +322,9 @@ void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
case DrmPlugin::kDrmPluginEventKeysChange:
jwhat = gEventWhat.kWhatKeyStatusChange;
break;
+ case DrmPlugin::kDrmPluginEventSessionLostState:
+ jwhat = gEventWhat.kWhatSessionLostState;
+ break;
default:
ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
return;
@@ -343,6 +358,30 @@ static void throwStateException(JNIEnv *env, const char *msg, status_t err) {
env->Throw(static_cast<jthrowable>(exception));
}
+static void throwSessionException(JNIEnv *env, const char *msg, status_t err) {
+ ALOGE("Session exception: %s (%d)", msg, err);
+
+ jint jErrorCode = 0;
+ switch(err) {
+ case ERROR_DRM_RESOURCE_CONTENTION:
+ jErrorCode = gSessionExceptionErrorCodes.kResourceContention;
+ break;
+ default:
+ break;
+ }
+
+ jobject exception = env->NewObject(gFields.sessionException.classId,
+ gFields.sessionException.init, static_cast<int>(err),
+ env->NewStringUTF(msg));
+
+ env->SetIntField(exception, gFields.sessionException.errorCode, jErrorCode);
+ env->Throw(static_cast<jthrowable>(exception));
+}
+
+static bool isSessionException(status_t err) {
+ return err == ERROR_DRM_RESOURCE_CONTENTION;
+}
+
static bool throwExceptionAsNecessary(
JNIEnv *env, status_t err, const char *msg = NULL) {
@@ -370,7 +409,7 @@ static bool throwExceptionAsNecessary(
case ERROR_DRM_CANNOT_HANDLE:
drmMessage = "Invalid parameter or data format";
break;
- case ERROR_DRM_TAMPER_DETECTED:
+ case ERROR_DRM_INVALID_STATE:
drmMessage = "Invalid state";
break;
default:
@@ -399,6 +438,9 @@ static bool throwExceptionAsNecessary(
jniThrowException(env, "android/media/MediaDrmResetException",
"mediaserver died");
return true;
+ } else if (isSessionException(err)) {
+ throwSessionException(env, msg, err);
+ return true;
} else if (err != OK) {
String8 errbuf;
if (drmMessage != NULL) {
@@ -705,6 +747,8 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_STATUS_CHANGE", "I");
gEventWhat.kWhatKeyStatusChange = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "SESSION_LOST_STATE", "I");
+ gEventWhat.kWhatSessionLostState = env->GetStaticIntField(clazz, field);
GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
@@ -831,6 +875,14 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
GET_METHOD_ID(gFields.stateException.init, clazz, "<init>", "(ILjava/lang/String;)V");
gFields.stateException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ FIND_CLASS(clazz, "android/media/MediaDrm$SessionException");
+ GET_METHOD_ID(gFields.sessionException.init, clazz, "<init>", "(ILjava/lang/String;)V");
+ gFields.sessionException.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_FIELD_ID(gFields.sessionException.errorCode, clazz, "mErrorCode", "I");
+
+ GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
+ gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
}
static void android_media_MediaDrm_native_setup(
diff --git a/native/android/Android.bp b/native/android/Android.bp
index fdcfc446a448..73d4c4522010 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -49,6 +49,7 @@ cc_library_shared {
"sharedmem.cpp",
"storage_manager.cpp",
"surface_texture.cpp",
+ "surface_control.cpp",
"system_fonts.cpp",
"trace.cpp",
],
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 537aed498cd2..8be8eda06a59 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -205,6 +205,9 @@ LIBANDROID {
AStorageManager_mountObb;
AStorageManager_new;
AStorageManager_unmountObb;
+ ASurfaceControl_create; # introduced=29
+ ASurfaceControl_createFromWindow; # introduced=29
+ ASurfaceControl_destroy; # introduced=29
ASurfaceTexture_acquireANativeWindow; # introduced=28
ASurfaceTexture_attachToGLContext; # introduced=28
ASurfaceTexture_detachFromGLContext; # introduced=28
@@ -213,6 +216,16 @@ LIBANDROID {
ASurfaceTexture_getTransformMatrix; # introduced=28
ASurfaceTexture_release; # introduced=28
ASurfaceTexture_updateTexImage; # introduced=28
+ ASurfaceTransaction_apply; # introduced=29
+ ASurfaceTransaction_create; # introduced=29
+ ASurfaceTransaction_delete; # introduced=29
+ ASurfaceTransaction_setBuffer; # introduced=29
+ ASurfaceTransaction_setBufferTransparency; # introduced=29
+ ASurfaceTransaction_setDamageRegion; # introduced=29
+ ASurfaceTransaction_setGeometry; # introduced=29
+ ASurfaceTransaction_setOnComplete; # introduced=29
+ ASurfaceTransaction_setVisibility; # introduced=29
+ ASurfaceTransaction_setZOrder; # introduced=29
ASystemFontIterator_open; # introduced=29
ASystemFontIterator_close; # introduced=29
ASystemFontIterator_next; # introduced=29
diff --git a/native/android/sharedmem.cpp b/native/android/sharedmem.cpp
index 757aaecab40d..4410bd6fbeed 100644
--- a/native/android/sharedmem.cpp
+++ b/native/android/sharedmem.cpp
@@ -71,7 +71,7 @@ int ASharedMemory_dupFromJava(JNIEnv* env, jobject javaSharedMemory) {
}
int fd = env->CallIntMethod(javaSharedMemory, sSharedMemory.getFd);
if (fd != -1) {
- fd = dup(fd);
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
}
return fd;
}
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
new file mode 100644
index 000000000000..ead5b0b37f4b
--- /dev/null
+++ b/native/android/surface_control.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2018 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 <android/native_window.h>
+#include <android/surface_control.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+
+using namespace android;
+
+using Transaction = SurfaceComposerClient::Transaction;
+
+#define CHECK_NOT_NULL(name) \
+ LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
+
+#define CHECK_VALID_RECT(name) \
+ LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \
+ "invalid arg passed as " #name " argument");
+
+Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) {
+ return reinterpret_cast<Transaction*>(aSurfaceTransaction);
+}
+
+SurfaceControl* ASurfaceControl_to_SurfaceControl(ASurfaceControl* aSurfaceControl) {
+ return reinterpret_cast<SurfaceControl*>(aSurfaceControl);
+}
+
+void SurfaceControl_acquire(SurfaceControl* surfaceControl) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ surfaceControl->incStrong((void*)SurfaceControl_acquire);
+}
+
+void SurfaceControl_release(SurfaceControl* surfaceControl) {
+ // incStrong/decStrong token must be the same, doesn't matter what it is
+ surfaceControl->decStrong((void*)SurfaceControl_acquire);
+}
+
+ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const char* debug_name) {
+ CHECK_NOT_NULL(window);
+ CHECK_NOT_NULL(debug_name);
+
+ sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+ if (client->initCheck() != NO_ERROR) {
+ return nullptr;
+ }
+
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+ sp<SurfaceControl> surfaceControl =
+ client->createWithSurfaceParent(String8(debug_name), 0 /* width */, 0 /* height */,
+ // Format is only relevant for buffer queue layers.
+ PIXEL_FORMAT_UNKNOWN /* format */, flags,
+ static_cast<Surface*>(window));
+ if (!surfaceControl) {
+ return nullptr;
+ }
+
+ SurfaceControl_acquire(surfaceControl.get());
+ return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) {
+ CHECK_NOT_NULL(parent);
+ CHECK_NOT_NULL(debug_name);
+
+ SurfaceComposerClient* client = ASurfaceControl_to_SurfaceControl(parent)->getClient().get();
+
+ SurfaceControl* surfaceControlParent = ASurfaceControl_to_SurfaceControl(parent);
+
+ uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState;
+ sp<SurfaceControl> surfaceControl =
+ client->createSurface(String8(debug_name), 0 /* width */, 0 /* height */,
+ // Format is only relevant for buffer queue layers.
+ PIXEL_FORMAT_UNKNOWN /* format */, flags,
+ surfaceControlParent);
+ if (!surfaceControl) {
+ return nullptr;
+ }
+
+ SurfaceControl_acquire(surfaceControl.get());
+ return reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
+}
+
+void ASurfaceControl_destroy(ASurfaceControl* aSurfaceControl) {
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+
+ Transaction().reparent(surfaceControl, nullptr).apply();
+ SurfaceControl_release(surfaceControl.get());
+}
+
+ASurfaceTransaction* ASurfaceTransaction_create() {
+ Transaction* transaction = new Transaction;
+ return reinterpret_cast<ASurfaceTransaction*>(transaction);
+}
+
+void ASurfaceTransaction_delete(ASurfaceTransaction* aSurfaceTransaction) {
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+ delete transaction;
+}
+
+void ASurfaceTransaction_apply(ASurfaceTransaction* aSurfaceTransaction) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->apply();
+}
+
+void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, void* context,
+ ASurfaceTransaction_OnComplete func) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(context);
+ CHECK_NOT_NULL(func);
+
+ TransactionCompletedCallbackTakesContext callback = [func](void* callback_context,
+ const TransactionStats& stats) {
+ int fence = (stats.presentFence) ? stats.presentFence->dup() : -1;
+ (*func)(callback_context, fence);
+ };
+
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->addTransactionCompletedCallback(callback, context);
+}
+
+void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ int8_t visibility) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ switch (visibility) {
+ case ASURFACE_TRANSACTION_VISIBILITY_SHOW:
+ transaction->show(surfaceControl);
+ break;
+ case ASURFACE_TRANSACTION_VISIBILITY_HIDE:
+ transaction->hide(surfaceControl);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("invalid visibility %d", visibility);
+ }
+}
+
+void ASurfaceTransaction_setZOrder(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ int32_t z_order) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->setLayer(surfaceControl, z_order);
+}
+
+void ASurfaceTransaction_setBuffer(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ AHardwareBuffer* buffer, int fence_fd) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ sp<GraphicBuffer> graphic_buffer(reinterpret_cast<GraphicBuffer*>(buffer));
+
+ transaction->setBuffer(surfaceControl, graphic_buffer);
+ if (fence_fd != -1) {
+ sp<Fence> fence = new Fence(fence_fd);
+ transaction->setAcquireFence(surfaceControl, fence);
+ }
+}
+
+void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl, const ARect& source,
+ const ARect& destination, int32_t transform) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+ CHECK_VALID_RECT(source);
+ CHECK_VALID_RECT(destination);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ transaction->setCrop(surfaceControl, static_cast<const Rect&>(source));
+ transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination));
+ transaction->setTransform(surfaceControl, transform);
+}
+
+void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* aSurfaceTransaction,
+ ASurfaceControl* aSurfaceControl,
+ int8_t transparency) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ uint32_t flags = (transparency == ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE) ?
+ layer_state_t::eLayerOpaque : 0;
+ transaction->setFlags(surfaceControl, flags, layer_state_t::eLayerOpaque);
+}
+
+void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+ const ARect rects[], uint32_t count) {
+ CHECK_NOT_NULL(aSurfaceTransaction);
+ CHECK_NOT_NULL(aSurfaceControl);
+
+ sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+ Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+ Region region;
+ for (uint32_t i = 0; i < count; ++i) {
+ region.merge(static_cast<const Rect&>(rects[i]));
+ }
+
+ transaction->setSurfaceDamageRegion(surfaceControl, region);
+}
diff --git a/native/webview/plat_support/draw_fn.h b/native/webview/plat_support/draw_fn.h
index 6afd8837594c..bb2ee9b5da04 100644
--- a/native/webview/plat_support/draw_fn.h
+++ b/native/webview/plat_support/draw_fn.h
@@ -109,8 +109,15 @@ struct AwDrawFn_DrawVkParams {
// Input: Format of the destination surface.
VkFormat format;
- // Input: Color space transformation from linear RGB to D50-adapted XYZ
- float matrix[9];
+ // Input: Color space parameters.
+ float transfer_function_g;
+ float transfer_function_a;
+ float transfer_function_b;
+ float transfer_function_c;
+ float transfer_function_d;
+ float transfer_function_e;
+ float transfer_function_f;
+ float color_space_toXYZD50[9];
// Input: current clip rect
int clip_left;
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index a9d8f62d53f4..95df5f269467 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -27,6 +27,7 @@ import android.os.Process;
import android.service.notification.NotificationAssistantService;
import android.text.TextUtils;
import android.util.LruCache;
+import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
@@ -65,13 +66,13 @@ public class SmartActionsHelper {
private static final int MAX_MESSAGES_TO_EXTRACT = 5;
private static final int MAX_RESULT_ID_TO_CACHE = 20;
- private static final ConversationActions.TypeConfig TYPE_CONFIG =
- new ConversationActions.TypeConfig.Builder().setIncludedTypes(
- Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+ private static final TextClassifier.EntityConfig TYPE_CONFIG =
+ new TextClassifier.EntityConfig.Builder().setIncludedTypes(
+ Collections.singletonList(ConversationAction.TYPE_TEXT_REPLY))
.includeTypesFromTextClassifier(false)
.build();
private static final List<String> HINTS =
- Collections.singletonList(ConversationActions.HINT_FOR_NOTIFICATION);
+ Collections.singletonList(ConversationActions.Request.HINT_FOR_NOTIFICATION);
private Context mContext;
@Nullable
@@ -137,7 +138,7 @@ public class SmartActionsHelper {
ConversationActions conversationActionsResult =
mTextClassifier.suggestConversationActions(request);
- List<ConversationActions.ConversationAction> conversationActions =
+ List<ConversationAction> conversationActions =
conversationActionsResult.getConversationActions();
ArrayList<CharSequence> replies = conversationActions.stream()
.map(conversationAction -> conversationAction.getTextReply())
@@ -193,7 +194,7 @@ public class SmartActionsHelper {
}
TextClassifierEvent textClassifierEvent =
createTextClassifierEventBuilder(TextClassifierEvent.TYPE_SMART_ACTION, resultId)
- .setEntityType(ConversationActions.TYPE_TEXT_REPLY)
+ .setEntityType(ConversationAction.TYPE_TEXT_REPLY)
.build();
mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
index 7d74788e21c0..7b7ce3d87f31 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionHelperTest.java
@@ -32,6 +32,7 @@ import android.service.notification.NotificationAssistantService;
import android.service.notification.StatusBarNotification;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
+import android.view.textclassifier.ConversationAction;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
@@ -65,9 +66,10 @@ public class SmartActionHelperTest {
private static final String NOTIFICATION_KEY = "key";
private static final String RESULT_ID = "id";
- private static final ConversationActions.ConversationAction REPLY_ACTION =
- new ConversationActions.ConversationAction.Builder(
- ConversationActions.TYPE_TEXT_REPLY).setTextReply("Home").build();
+ private static final ConversationAction REPLY_ACTION =
+ new ConversationAction.Builder(ConversationAction.TYPE_TEXT_REPLY)
+ .setTextReply("Home")
+ .build();
private SmartActionsHelper mSmartActionsHelper;
private Context mContext;
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 0b0f1eca7aa5..7f8bb93ae023 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,7 @@
package="com.android.mainline.networkstack"
android:sharedUserId="android.uid.networkstack">
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 94ea1b931348..4077d93d700b 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -545,7 +545,9 @@ public class NetworkMonitor extends StateMachine {
return HANDLED;
case CMD_FORCE_REEVALUATION:
case CMD_CAPTIVE_PORTAL_RECHECK:
- log("Forcing reevaluation for UID " + message.arg1);
+ final int dnsCount = mDnsStallDetector.getConsecutiveTimeoutCount();
+ validationLog("Forcing reevaluation for UID " + message.arg1
+ + ". Dns signal count: " + dnsCount);
mUidResponsibleForReeval = message.arg1;
transitionTo(mEvaluatingState);
return HANDLED;
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index aed02a268aea..8090169a4245 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -41,10 +41,6 @@ public class VisibilityLoggerMixin implements LifecycleObserver {
private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
private long mVisibleTimestamp;
- private VisibilityLoggerMixin() {
- mMetricsCategory = METRICS_CATEGORY_UNKNOWN;
- }
-
public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
mMetricsCategory = metricsCategory;
mMetricsFeature = metricsFeature;
@@ -81,12 +77,4 @@ public class VisibilityLoggerMixin implements LifecycleObserver {
MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
MetricsProto.MetricsEvent.VIEW_UNKNOWN);
}
-
- /** Returns elapsed time since onResume() */
- public long elapsedTimeSinceVisible() {
- if (mVisibleTimestamp == 0) {
- return 0;
- }
- return SystemClock.elapsedRealtime() - mVisibleTimestamp;
- }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index e853399133aa..ef90dc981870 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -28,8 +28,8 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteStatement;
-import android.media.AudioSystem;
import android.media.AudioManager;
+import android.media.AudioSystem;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Environment;
@@ -1104,9 +1104,7 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
if (upgradeVersion == 77) {
- // Introduce "vibrate when ringing" setting
- loadVibrateWhenRingingSetting(db);
-
+ // "vibrate when ringing" setting moved to SettingsProvider version 168
upgradeVersion = 78;
}
@@ -2223,8 +2221,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
} finally {
if (stmt != null) stmt.close();
}
-
- loadVibrateWhenRingingSetting(db);
}
private void loadVibrateSetting(SQLiteDatabase db, boolean deleteOld) {
@@ -2250,24 +2246,6 @@ class DatabaseHelper extends SQLiteOpenHelper {
}
}
- private void loadVibrateWhenRingingSetting(SQLiteDatabase db) {
- // The default should be off. VIBRATE_SETTING_ONLY_SILENT should also be ignored here.
- // Phone app should separately check whether AudioManager#getRingerMode() returns
- // RINGER_MODE_VIBRATE, with which the device should vibrate anyway.
- int vibrateSetting = getIntValueFromSystem(db, Settings.System.VIBRATE_ON,
- AudioManager.VIBRATE_SETTING_OFF);
- boolean vibrateWhenRinging = ((vibrateSetting & 3) == AudioManager.VIBRATE_SETTING_ON);
-
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
- + " VALUES(?,?);");
- loadSetting(stmt, Settings.System.VIBRATE_WHEN_RINGING, vibrateWhenRinging ? 1 : 0);
- } finally {
- if (stmt != null) stmt.close();
- }
- }
-
private void loadSettings(SQLiteDatabase db) {
loadSystemSettings(db);
loadSecureSettings(db);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index fa95bf2ee302..9b775e058ea8 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -129,6 +129,7 @@
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
+ <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
<uses-permission android:name="android.permission.ACTIVITY_EMBEDDING" />
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 2530abc765da..afb978174784 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -56,6 +56,7 @@ import com.google.android.collect.Lists;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.annotation.MainThread;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Notification;
@@ -799,6 +800,18 @@ public class BugreportProgressService extends Service {
Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent);
return;
}
+ final int max = intent.getIntExtra(EXTRA_MAX, -1);
+ final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT);
+ final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
+ final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
+ onBugreportFinished(id, bugreportFile, screenshotFile, shareTitle, shareDescription, max);
+ }
+
+ /**
+ * Wraps up bugreport generation and triggers a notification to share the bugreport.
+ */
+ private void onBugreportFinished(int id, File bugreportFile, @Nullable File screenshotFile,
+ String shareTitle, String shareDescription, int max) {
mInfoDialog.onBugreportFinished();
BugreportInfo info = getInfo(id);
if (info == null) {
@@ -809,22 +822,17 @@ public class BugreportProgressService extends Service {
}
info.renameScreenshots(mScreenshotsDir);
info.bugreportFile = bugreportFile;
+ if (screenshotFile != null) {
+ info.addScreenshot(screenshotFile);
+ }
- final int max = intent.getIntExtra(EXTRA_MAX, -1);
if (max != -1) {
MetricsLogger.histogram(this, "dumpstate_duration", max);
info.max = max;
}
- final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT);
- if (screenshot != null) {
- info.addScreenshot(screenshot);
- }
-
- final String shareTitle = intent.getStringExtra(EXTRA_TITLE);
if (!TextUtils.isEmpty(shareTitle)) {
info.title = shareTitle;
- final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION);
if (!TextUtils.isEmpty(shareDescription)) {
info.shareDescription= shareDescription;
}
@@ -1944,6 +1952,23 @@ public class BugreportProgressService extends Service {
}
@Override
+ public void onProgress(int progress) throws RemoteException {
+ // TODO(b/111441001): change max argument?
+ updateProgressInfo(progress, CAPPED_MAX);
+ }
+
+ @Override
+ public void onError(int errorCode) throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
+ public void onFinished(long durationMs, String title, String description)
+ throws RemoteException {
+ // TODO(b/111441001): implement
+ }
+
+ @Override
public void onProgressUpdated(int progress) throws RemoteException {
/*
* Checks whether the progress changed in a way that should be displayed to the user:
@@ -1964,21 +1989,7 @@ public class BugreportProgressService extends Service {
}
if (newPercentage > oldPercentage) {
- if (DEBUG) {
- if (progress != info.progress) {
- Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
- + ") from " + info.progress + " to " + progress);
- }
- if (max != info.max) {
- Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
- + ") from " + info.max + " to " + max);
- }
- }
- info.progress = progress;
- info.max = max;
- info.lastUpdate = System.currentTimeMillis();
-
- updateProgress(info);
+ updateProgressInfo(progress, max);
}
}
@@ -2000,5 +2011,23 @@ public class BugreportProgressService extends Service {
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("token: "); pw.println(token);
}
+
+ private void updateProgressInfo(int progress, int max) {
+ if (DEBUG) {
+ if (progress != info.progress) {
+ Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id
+ + ") from " + info.progress + " to " + progress);
+ }
+ if (max != info.max) {
+ Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id
+ + ") from " + info.max + " to " + max);
+ }
+ }
+ info.progress = progress;
+ info.max = max;
+ info.lastUpdate = System.currentTimeMillis();
+
+ updateProgress(info);
+ }
}
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 1c1a1404eacd..b4f2711ef9d2 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -87,6 +87,7 @@
<uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
<uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
<uses-permission android:name="android.permission.START_ANY_ACTIVITY" />
+ <uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
index ecfbfb434800..c8e0845a9144 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml
@@ -25,12 +25,18 @@
android:focusable="true"
android:layout_gravity="center_vertical">
- <ImageView
- android:id="@+id/app_icon"
+ <FrameLayout
android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
- android:layout_gravity="start|center_vertical"
- />
+ android:layout_gravity="start|center_vertical">
+
+ <ImageView
+ android:id="@+id/app_icon"
+ android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size"
+ android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size"
+ android:layout_gravity="center"
+ />
+ </FrameLayout>
<TextView
android:id="@+id/app_name"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ef16bcaf0fd2..5a00b4526c32 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -952,6 +952,8 @@
<dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
<!-- Height and width of Application icons in Ongoing App Ops dialog -->
<dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
+ <!-- Height and width of Plus sign in Ongoing App Ops dialog -->
+ <dimen name="ongoing_appops_dialog_app_plus_size">24dp</dimen>
<!-- Height of line in Ongoing App Ops dialog-->
<dimen name="ongoing_appops_dialog_line_height">48dp</dimen>
<!-- Side margin of title in Ongoing App Ops dialog -->
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index 6ed1ebad8e51..77e25e324915 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -20,6 +20,7 @@ import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.res.ColorStateList
+import android.util.IconDrawableFactory
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -37,11 +38,22 @@ class OngoingPrivacyDialog constructor(
private val iconSize = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_size)
+ private val plusSize = context.resources.getDimensionPixelSize(
+ R.dimen.ongoing_appops_dialog_app_plus_size)
private val iconColor = context.resources.getColor(
com.android.internal.R.color.text_color_primary, context.theme)
+ private val plusColor: Int
private val iconMargin = context.resources.getDimensionPixelSize(
R.dimen.ongoing_appops_dialog_icon_margin)
private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps)
+ private val iconFactory = IconDrawableFactory.newInstance(context, true)
+
+ init {
+ val a = context.theme.obtainStyledAttributes(
+ intArrayOf(com.android.internal.R.attr.colorAccent))
+ plusColor = a.getColor(0, 0)
+ a.recycle()
+ }
fun createDialog(): Dialog {
val builder = AlertDialog.Builder(context).apply {
@@ -87,9 +99,15 @@ class OngoingPrivacyDialog constructor(
numItems - MAX_ITEMS
)
val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView
+ val lp = overflowPlus.layoutParams.apply {
+ height = plusSize
+ width = plusSize
+ }
+ overflowPlus.layoutParams = lp
overflowPlus.apply {
- imageTintList = ColorStateList.valueOf(iconColor)
- setImageDrawable(context.getDrawable(R.drawable.plus))
+ val plus = context.getDrawable(R.drawable.plus)
+ imageTintList = ColorStateList.valueOf(plusColor)
+ setImageDrawable(plus)
}
}
@@ -114,7 +132,7 @@ class OngoingPrivacyDialog constructor(
}
app.icon.let {
- appIcon.setImageDrawable(it)
+ appIcon.setImageDrawable(iconFactory.getShadowedIcon(it))
}
appName.text = app.applicationName
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 848f2bd1a6fe..2fa1ddee0fd9 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := WallpaperCropper
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/packages/WallpaperCropper/CleanSpec.mk b/packages/WallpaperCropper/CleanSpec.mk
new file mode 100644
index 000000000000..e6d8d5a774f1
--- /dev/null
+++ b/packages/WallpaperCropper/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2019 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/WallpaperCropper)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 5b45a08af9b4..44edb568573c 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6794,6 +6794,13 @@ message MetricsEvent {
// OS: Q
NOTIFICATION_BLOCKING_HELPER = 1621;
+ // ACTION: Tap & Pay -> Default Application Setting -> Use Forground
+ // OS: Q
+ ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622;
+
+ // ACTION: Tap & Pay -> Default Application Setting -> Use Default
+ // OS: Q
+ ACTION_NFC_PAYMENT_ALWAYS_SETTING = 1623;
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index e4ce62d0a5b5..4a1e5b9910bf 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -23,9 +23,9 @@ import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.Signature;
import android.content.pm.SigningInfo;
import android.os.Build;
@@ -49,9 +49,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-
import java.util.Objects;
+import java.util.Set;
/**
* We back up the signatures of each package so that during a system restore,
@@ -95,6 +94,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
// is coming from pre-Android P device.
private static final int UNDEFINED_ANCESTRAL_RECORD_VERSION = -1;
+ private int mUserId;
private List<PackageInfo> mAllPackages;
private PackageManager mPackageManager;
// version & signature info of each app in a restore set
@@ -129,17 +129,18 @@ public class PackageManagerBackupAgent extends BackupAgent {
// We're constructed with the set of applications that are participating
// in backup. This set changes as apps are installed & removed.
- public PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
- init(packageMgr, packages);
+ public PackageManagerBackupAgent(
+ PackageManager packageMgr, List<PackageInfo> packages, int userId) {
+ init(packageMgr, packages, userId);
}
- public PackageManagerBackupAgent(PackageManager packageMgr) {
- init(packageMgr, null);
+ public PackageManagerBackupAgent(PackageManager packageMgr, int userId) {
+ init(packageMgr, null, userId);
evaluateStorablePackages();
}
- private void init(PackageManager packageMgr, List<PackageInfo> packages) {
+ private void init(PackageManager packageMgr, List<PackageInfo> packages, int userId) {
mPackageManager = packageMgr;
mAllPackages = packages;
mRestoredSignatures = null;
@@ -147,17 +148,19 @@ public class PackageManagerBackupAgent extends BackupAgent {
mStoredSdkVersion = Build.VERSION.SDK_INT;
mStoredIncrementalVersion = Build.VERSION.INCREMENTAL;
+ mUserId = userId;
}
// We will need to refresh our understanding of what is eligible for
// backup periodically; this entry point serves that purpose.
public void evaluateStorablePackages() {
- mAllPackages = getStorableApplications(mPackageManager);
+ mAllPackages = getStorableApplications(mPackageManager, mUserId);
}
- public static List<PackageInfo> getStorableApplications(PackageManager pm) {
- List<PackageInfo> pkgs;
- pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNING_CERTIFICATES);
+ /** Gets all packages installed on user {@code userId} eligible for backup. */
+ public static List<PackageInfo> getStorableApplications(PackageManager pm, int userId) {
+ List<PackageInfo> pkgs =
+ pm.getInstalledPackagesAsUser(PackageManager.GET_SIGNING_CERTIFICATES, userId);
int N = pkgs.size();
for (int a = N-1; a >= 0; a--) {
PackageInfo pkg = pkgs.get(a);
@@ -237,8 +240,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
ComponentName home = getPreferredHomeComponent();
if (home != null) {
try {
- homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
- PackageManager.GET_SIGNING_CERTIFICATES);
+ homeInfo = mPackageManager.getPackageInfoAsUser(home.getPackageName(),
+ PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
homeVersion = homeInfo.getLongVersionCode();
SigningInfo signingInfo = homeInfo.signingInfo;
@@ -315,8 +318,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
} else {
PackageInfo info = null;
try {
- info = mPackageManager.getPackageInfo(packName,
- PackageManager.GET_SIGNING_CERTIFICATES);
+ info = mPackageManager.getPackageInfoAsUser(packName,
+ PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
} catch (NameNotFoundException e) {
// Weird; we just found it, and now are told it doesn't exist.
// Treat it as having been removed from the device.
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index ed6a46cc58aa..3a8966a04055 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -249,11 +249,11 @@ public class UserBackupManagerService {
private final TransportManager mTransportManager;
private final HandlerThread mUserBackupThread;
- private Context mContext;
- private PackageManager mPackageManager;
- private IPackageManager mPackageManagerBinder;
- private IActivityManager mActivityManager;
- private ActivityManagerInternal mActivityManagerInternal;
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+ private final IPackageManager mPackageManagerBinder;
+ private final IActivityManager mActivityManager;
+ private final ActivityManagerInternal mActivityManagerInternal;
private PowerManager mPowerManager;
private final AlarmManager mAlarmManager;
private final IStorageManager mStorageManager;
@@ -496,11 +496,18 @@ public class UserBackupManagerService {
mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
mBaseStateDir.mkdirs();
if (!SELinux.restorecon(mBaseStateDir)) {
- Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir);
+ Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
-
+ // TODO(b/120424138): Remove when the system user moves out of the cache dir. The cache dir
+ // is managed by init.rc so we don't have to create it below.
+ if (userId != UserHandle.USER_SYSTEM) {
+ mDataDir.mkdirs();
+ if (!SELinux.restorecon(mDataDir)) {
+ Slog.w(TAG, "SELinux restorecon failed on " + mDataDir);
+ }
+ }
mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
// Receivers for scheduled backups and transport initialization operations.
@@ -797,7 +804,7 @@ public class UserBackupManagerService {
* non-lifecycle agent instance, so we manually set up the context topology for it.
*/
public BackupAgent makeMetadataAgent() {
- PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager);
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(mPackageManager, mUserId);
pmAgent.attach(mContext);
pmAgent.onCreate();
return pmAgent;
@@ -808,7 +815,7 @@ public class UserBackupManagerService {
*/
public PackageManagerBackupAgent makeMetadataAgent(List<PackageInfo> packages) {
PackageManagerBackupAgent pmAgent =
- new PackageManagerBackupAgent(mPackageManager, packages);
+ new PackageManagerBackupAgent(mPackageManager, packages, mUserId);
pmAgent.attach(mContext);
pmAgent.onCreate();
return pmAgent;
@@ -879,7 +886,7 @@ public class UserBackupManagerService {
boolean changed = false;
ArrayList<FullBackupEntry> schedule = null;
List<PackageInfo> apps =
- PackageManagerBackupAgent.getStorableApplications(mPackageManager);
+ PackageManagerBackupAgent.getStorableApplications(mPackageManager, mUserId);
if (mFullBackupScheduleFile.exists()) {
try (FileInputStream fstream = new FileInputStream(mFullBackupScheduleFile);
@@ -1428,8 +1435,7 @@ public class UserBackupManagerService {
mConnecting = true;
mConnectedAgent = null;
try {
- if (mActivityManager.bindBackupAgent(app.packageName, mode,
- UserHandle.USER_OWNER)) {
+ if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId)) {
Slog.d(TAG, "awaiting agent for " + app);
// success; wait for the agent to arrive
@@ -1460,11 +1466,7 @@ public class UserBackupManagerService {
}
}
if (agent == null) {
- try {
- mActivityManager.clearPendingBackup();
- } catch (RemoteException e) {
- // can't happen - ActivityManager is local
- }
+ mActivityManagerInternal.clearPendingBackup(mUserId);
}
return agent;
}
@@ -1488,7 +1490,7 @@ public class UserBackupManagerService {
public void clearApplicationDataSynchronous(String packageName, boolean keepSystemState) {
// Don't wipe packages marked allowClearUserData=false
try {
- PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
+ PackageInfo info = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) == 0) {
if (MORE_DEBUG) {
Slog.i(TAG, "allowClearUserData=false so not wiping "
@@ -1507,7 +1509,7 @@ public class UserBackupManagerService {
mClearingData = true;
try {
mActivityManager.clearApplicationUserData(
- packageName, keepSystemState, observer, 0);
+ packageName, keepSystemState, observer, mUserId);
} catch (RemoteException e) {
// can't happen because the activity manager is in this process
}
@@ -1616,8 +1618,8 @@ public class UserBackupManagerService {
continue;
}
try {
- PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNING_CERTIFICATES);
+ PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo,
mPackageManager)) {
BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
@@ -2339,8 +2341,8 @@ public class UserBackupManagerService {
if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
PackageInfo info;
try {
- info = mPackageManager.getPackageInfo(packageName,
- PackageManager.GET_SIGNING_CERTIFICATES);
+ info = mPackageManager.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
} catch (NameNotFoundException e) {
Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
return;
@@ -3258,7 +3260,7 @@ public class UserBackupManagerService {
if (packageName != null) {
PackageInfo app = null;
try {
- app = mPackageManager.getPackageInfo(packageName, 0);
+ app = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId);
} catch (NameNotFoundException nnf) {
Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
throw new IllegalArgumentException("Package " + packageName + " not found");
@@ -3362,7 +3364,7 @@ public class UserBackupManagerService {
mTransportManager.getCurrentTransportClient(callerLogString);
boolean eligible =
AppBackupUtils.appIsRunningAndEligibleForBackupWithTransport(
- transportClient, packageName, mPackageManager);
+ transportClient, packageName, mPackageManager, mUserId);
if (transportClient != null) {
mTransportManager.disposeOfTransportClient(transportClient, callerLogString);
}
@@ -3386,7 +3388,7 @@ public class UserBackupManagerService {
for (String packageName : packages) {
if (AppBackupUtils
.appIsRunningAndEligibleForBackupWithTransport(
- transportClient, packageName, mPackageManager)) {
+ transportClient, packageName, mPackageManager, mUserId)) {
eligibleApps.add(packageName);
}
}
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index ef7ff9270a66..862ca711e694 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -45,7 +45,6 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.SELinux;
-import android.os.UserHandle;
import android.os.WorkSource;
import com.android.internal.annotations.GuardedBy;
@@ -241,6 +240,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
private final boolean mUserInitiated;
private final boolean mNonIncremental;
private final int mCurrentOpToken;
+ private final int mUserId;
private final File mStateDirectory;
private final File mDataDirectory;
private final File mBlankStateFile;
@@ -320,6 +320,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
mQueueLock = mBackupManagerService.getQueueLock();
mBlankStateFile = new File(mStateDirectory, BLANK_STATE_FILE_NAME);
+ mUserId = backupManagerService.getUserId();
}
private void registerTask() {
@@ -480,8 +481,8 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
final PackageInfo packageInfo;
try {
packageInfo =
- mPackageManager.getPackageInfo(
- packageName, PackageManager.GET_SIGNING_CERTIFICATES);
+ mPackageManager.getPackageInfoAsUser(
+ packageName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
} catch (PackageManager.NameNotFoundException e) {
mReporter.onAgentUnknown(packageName);
throw AgentException.permanent(e);
@@ -770,8 +771,7 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable {
private void writeWidgetPayloadIfAppropriate(FileDescriptor fd, String pkgName)
throws IOException {
- // TODO: http://b/22388012
- byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, UserHandle.USER_SYSTEM);
+ byte[] widgetState = AppWidgetBackupBridge.getWidgetState(pkgName, mUserId);
File widgetFile = new File(mStateDirectory, pkgName + "_widget");
boolean priorStateExists = widgetFile.exists();
if (!priorStateExists && widgetState == null) {
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index e273b329d51a..0fa0f89e329e 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -54,6 +54,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
private final TransportManager mTransportManager;
private final String mTransportName;
private final UserBackupManagerService mBackupManagerService;
+ private final int mUserId;
@Nullable private final String mPackageName;
public RestoreSet[] mRestoreSets = null;
boolean mEnded = false;
@@ -67,6 +68,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
mPackageName = packageName;
mTransportManager = backupManagerService.getTransportManager();
mTransportName = transportName;
+ mUserId = backupManagerService.getUserId();
}
public void markTimedOut() {
@@ -304,7 +306,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
final PackageInfo app;
try {
- app = mBackupManagerService.getPackageManager().getPackageInfo(packageName, 0);
+ app = mBackupManagerService.getPackageManager().getPackageInfoAsUser(
+ packageName, 0, mUserId);
} catch (NameNotFoundException nnf) {
Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName);
return -1;
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 45a398f80351..c7f3315493b4 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -272,7 +272,7 @@ public class FullRestoreEngine extends RestoreEngine {
instream, mBackupManagerService.getContext(),
mDeleteObserver, mManifestSignatures,
mPackagePolicies, info, installerPackageName,
- bytesReadListener);
+ bytesReadListener, mBackupManagerService.getUserId());
// good to go; promote to ACCEPT
mPackagePolicies.put(pkg, isSuccessfullyInstalled
? RestorePolicy.ACCEPT
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index f7efad604e35..5284d94c2aa7 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -48,7 +48,6 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
@@ -81,6 +80,7 @@ import java.util.List;
public class PerformUnifiedRestoreTask implements BackupRestoreTask {
private UserBackupManagerService backupManagerService;
+ private final int mUserId;
private final TransportManager mTransportManager;
// Transport client we're working with to do the restore
private final TransportClient mTransportClient;
@@ -175,6 +175,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
@Nullable String[] filterSet,
OnTaskFinishedListener listener) {
this.backupManagerService = backupManagerService;
+ mUserId = backupManagerService.getUserId();
mTransportManager = backupManagerService.getTransportManager();
mEphemeralOpToken = backupManagerService.generateRandomIntegerToken();
mState = UnifiedRestoreState.INITIAL;
@@ -204,7 +205,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// We want everything and a pony
List<PackageInfo> apps =
PackageManagerBackupAgent.getStorableApplications(
- backupManagerService.getPackageManager());
+ backupManagerService.getPackageManager(), mUserId);
filterSet = packagesToNames(apps);
if (DEBUG) {
Slog.i(TAG, "Full restore; asking about " + filterSet.length + " apps");
@@ -221,7 +222,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
for (int i = 0; i < filterSet.length; i++) {
try {
PackageManager pm = backupManagerService.getPackageManager();
- PackageInfo info = pm.getPackageInfo(filterSet[i], 0);
+ PackageInfo info = pm.getPackageInfoAsUser(filterSet[i], 0, mUserId);
if ("android".equals(info.packageName)) {
hasSystem = true;
continue;
@@ -240,16 +241,16 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
if (hasSystem) {
try {
- mAcceptSet.add(0,
- backupManagerService.getPackageManager().getPackageInfo("android", 0));
+ mAcceptSet.add(0, backupManagerService.getPackageManager().getPackageInfoAsUser(
+ "android", 0, mUserId));
} catch (NameNotFoundException e) {
// won't happen; we know a priori that it's valid
}
}
if (hasSettings) {
try {
- mAcceptSet.add(backupManagerService.getPackageManager().getPackageInfo(
- SETTINGS_PACKAGE, 0));
+ mAcceptSet.add(backupManagerService.getPackageManager().getPackageInfoAsUser(
+ SETTINGS_PACKAGE, 0, mUserId));
} catch (NameNotFoundException e) {
// this one is always valid too
}
@@ -360,7 +361,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// If we're starting a full-system restore, set up to begin widget ID remapping
if (mIsSystemRestore) {
// TODO: http://b/22388012
- AppWidgetBackupBridge.restoreStarting(UserHandle.USER_SYSTEM);
+ AppWidgetBackupBridge.restoreStarting(mUserId);
}
try {
@@ -508,8 +509,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
try {
- mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo(
- pkgName, PackageManager.GET_SIGNING_CERTIFICATES);
+ mCurrentPackage = backupManagerService.getPackageManager().getPackageInfoAsUser(
+ pkgName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
} catch (NameNotFoundException e) {
// Whoops, we thought we could restore this package but it
// turns out not to be present. Skip it.
@@ -1079,7 +1080,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Kick off any work that may be needed regarding app widget restores
// TODO: http://b/22388012
- AppWidgetBackupBridge.restoreFinished(UserHandle.USER_SYSTEM);
+ AppWidgetBackupBridge.restoreFinished(mUserId);
// If this was a full-system restore, record the ancestral
// dataset information
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index e465c7e5264f..054879b077ad 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -91,10 +91,13 @@ public class AppBackupUtils {
* </ol>
*/
public static boolean appIsRunningAndEligibleForBackupWithTransport(
- @Nullable TransportClient transportClient, String packageName, PackageManager pm) {
+ @Nullable TransportClient transportClient,
+ String packageName,
+ PackageManager pm,
+ int userId) {
try {
- PackageInfo packageInfo = pm.getPackageInfo(packageName,
- PackageManager.GET_SIGNING_CERTIFICATES);
+ PackageInfo packageInfo = pm.getPackageInfoAsUser(packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES, userId);
ApplicationInfo applicationInfo = packageInfo.applicationInfo;
if (!appIsEligibleForBackup(applicationInfo, pm)
|| appIsStopped(applicationInfo)
diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
index df7e6d45ba0f..cce5b3b4e238 100644
--- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
@@ -72,7 +72,9 @@ public class RestoreUtils {
HashMap<String, Signature[]> manifestSignatures,
HashMap<String, RestorePolicy> packagePolicies,
FileMetadata info,
- String installerPackageName, BytesReadListener bytesReadListener) {
+ String installerPackageName,
+ BytesReadListener bytesReadListener,
+ int userId) {
boolean okay = true;
if (DEBUG) {
@@ -144,8 +146,8 @@ public class RestoreUtils {
uninstall = true;
} else {
try {
- PackageInfo pkg = packageManager.getPackageInfo(info.packageName,
- PackageManager.GET_SIGNING_CERTIFICATES);
+ PackageInfo pkg = packageManager.getPackageInfoAsUser(info.packageName,
+ PackageManager.GET_SIGNING_CERTIFICATES, userId);
if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP)
== 0) {
Slog.w(TAG, "Restore stream contains apk of package "
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3b08a00a65d2..bd6fa498934c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -920,8 +920,8 @@ public class ActivityManagerService extends IActivityManager.Stub
/**
* Backup/restore process management
*/
- String mBackupAppName = null;
- BackupRecord mBackupTarget = null;
+ @GuardedBy("this")
+ final SparseArray<BackupRecord> mBackupTargets = new SparseArray<>();
final ProviderMap mProviderMap;
@@ -4365,6 +4365,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers");
}
+ @GuardedBy("this")
private final void processStartTimedOutLocked(ProcessRecord app) {
final int pid = app.pid;
boolean gone = mPidsSelfLocked.removeIfNoThread(pid);
@@ -4385,7 +4386,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
}
removeLruProcessLocked(app);
- if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
+ final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+ if (backupTarget != null && backupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
mHandler.post(new Runnable() {
@Override
@@ -4393,7 +4395,7 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnected(app.info.packageName);
+ bm.agentDisconnectedForUser(app.userId, app.info.packageName);
} catch (RemoteException e) {
// Can't happen; the backup manager is local
}
@@ -4516,6 +4518,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (DEBUG_ALL) Slog.v(
TAG, "New app record " + app
+ " thread=" + thread.asBinder() + " pid=" + pid);
+ final BackupRecord backupTarget = mBackupTargets.get(app.userId);
try {
int testMode = ApplicationThreadConstants.DEBUG_OFF;
if (mDebugApp != null && mDebugApp.equals(processName)) {
@@ -4537,11 +4540,11 @@ public class ActivityManagerService extends IActivityManager.Stub
// If the app is being launched for restore or full backup, set it up specially
boolean isRestrictedBackupMode = false;
- if (mBackupTarget != null && mBackupAppName.equals(processName)) {
- isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID
- && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
- || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
- || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
+ if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) {
+ isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID
+ && ((backupTarget.backupMode == BackupRecord.RESTORE)
+ || (backupTarget.backupMode == BackupRecord.RESTORE_FULL)
+ || (backupTarget.backupMode == BackupRecord.BACKUP_FULL));
}
final ActiveInstrumentation instr = app.getActiveInstrumentation();
@@ -4749,15 +4752,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// Check whether the next backup agent is in this process...
- if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
+ if (!badApp && backupTarget != null && backupTarget.app == app) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
"New app is backup target, launching agent for " + app);
- notifyPackageUse(mBackupTarget.appInfo.packageName,
+ notifyPackageUse(backupTarget.appInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
try {
- thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
- compatibilityInfoForPackage(mBackupTarget.appInfo),
- mBackupTarget.backupMode);
+ thread.scheduleCreateBackupAgent(backupTarget.appInfo,
+ compatibilityInfoForPackage(backupTarget.appInfo),
+ backupTarget.backupMode);
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
badApp = true;
@@ -13224,16 +13227,17 @@ public class ActivityManagerService extends IActivityManager.Stub
app.receivers.clear();
// If the app is undergoing backup, tell the backup manager about it
- if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
+ final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+ if (backupTarget != null && app.pid == backupTarget.app.pid) {
if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "
- + mBackupTarget.appInfo + " died during backup");
+ + backupTarget.appInfo + " died during backup");
mHandler.post(new Runnable() {
@Override
public void run(){
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentDisconnected(app.info.packageName);
+ bm.agentDisconnectedForUser(app.userId, app.info.packageName);
} catch (RemoteException e) {
// can't happen; backup manager is local
}
@@ -13573,7 +13577,11 @@ public class ActivityManagerService extends IActivityManager.Stub
// instantiated. The backup agent will invoke backupAgentCreated() on the
// activity manager to announce its creation.
public boolean bindBackupAgent(String packageName, int backupMode, int userId) {
- if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode);
+ if (DEBUG_BACKUP) {
+ Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode="
+ + backupMode + " userId=" + userId + " callingUid = " + Binder.getCallingUid()
+ + " uid = " + Process.myUid());
+ }
enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent");
IPackageManager pm = AppGlobals.getPackageManager();
@@ -13625,10 +13633,10 @@ public class ActivityManagerService extends IActivityManager.Stub
proc.inFullBackup = true;
}
r.app = proc;
- oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+ final BackupRecord backupTarget = mBackupTargets.get(userId);
+ oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
newBackupUid = proc.inFullBackup ? r.appInfo.uid : -1;
- mBackupTarget = r;
- mBackupAppName = app.packageName;
+ mBackupTargets.put(userId, r);
// Try not to kill the process during backup
updateOomAdjLocked(proc, true);
@@ -13663,14 +13671,14 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
}
- @Override
- public void clearPendingBackup() {
- if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "clearPendingBackup");
- enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
+ private void clearPendingBackup(int userId) {
+ if (DEBUG_BACKUP) {
+ Slog.v(TAG_BACKUP, "clearPendingBackup: userId = " + userId + " callingUid = "
+ + Binder.getCallingUid() + " uid = " + Process.myUid());
+ }
synchronized (this) {
- mBackupTarget = null;
- mBackupAppName = null;
+ mBackupTargets.delete(userId);
}
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
@@ -13678,12 +13686,19 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// A backup agent has just come up
+ @Override
public void backupAgentCreated(String agentPackageName, IBinder agent) {
- if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName
- + " = " + agent);
+ final int callingUserId = UserHandle.getCallingUserId();
+ if (DEBUG_BACKUP) {
+ Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent
+ + " callingUserId = " + callingUserId + " callingUid = "
+ + Binder.getCallingUid() + " uid = " + Process.myUid());
+ }
synchronized(this) {
- if (!agentPackageName.equals(mBackupAppName)) {
+ final BackupRecord backupTarget = mBackupTargets.get(callingUserId);
+ String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName;
+ if (!agentPackageName.equals(backupAppName)) {
Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
return;
}
@@ -13693,7 +13708,7 @@ public class ActivityManagerService extends IActivityManager.Stub
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
- bm.agentConnected(agentPackageName, agent);
+ bm.agentConnectedForUser(callingUserId, agentPackageName, agent);
} catch (RemoteException e) {
// can't happen; the backup manager service is local
} catch (Exception e) {
@@ -13706,7 +13721,12 @@ public class ActivityManagerService extends IActivityManager.Stub
// done with this agent
public void unbindBackupAgent(ApplicationInfo appInfo) {
- if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo);
+ if (DEBUG_BACKUP) {
+ Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo + " appInfo.uid = "
+ + appInfo.uid + " callingUid = " + Binder.getCallingUid() + " uid = "
+ + Process.myUid());
+ }
+
enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "unbindBackupAgent");
if (appInfo == null) {
Slog.w(TAG, "unbind backup agent for null app");
@@ -13715,24 +13735,27 @@ public class ActivityManagerService extends IActivityManager.Stub
int oldBackupUid;
+ final int userId = UserHandle.getUserId(appInfo.uid);
synchronized(this) {
+ final BackupRecord backupTarget = mBackupTargets.get(userId);
+ String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName;
try {
- if (mBackupAppName == null) {
+ if (backupAppName == null) {
Slog.w(TAG, "Unbinding backup agent with no active backup");
return;
}
- if (!mBackupAppName.equals(appInfo.packageName)) {
+ if (!backupAppName.equals(appInfo.packageName)) {
Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
return;
}
// Not backing this app up any more; reset its OOM adjustment
- final ProcessRecord proc = mBackupTarget.app;
+ final ProcessRecord proc = backupTarget.app;
updateOomAdjLocked(proc, true);
proc.inFullBackup = false;
- oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
+ oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
// If the app crashed during backup, 'thread' will be null here
if (proc.thread != null) {
@@ -13745,8 +13768,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
} finally {
- mBackupTarget = null;
- mBackupAppName = null;
+ mBackupTargets.delete(userId);
}
}
@@ -17771,6 +17793,11 @@ public class ActivityManagerService extends IActivityManager.Stub
public boolean isAppForeground(int uid) {
return ActivityManagerService.this.isAppForeground(uid);
}
+
+ @Override
+ public void clearPendingBackup(int userId) {
+ ActivityManagerService.this.clearPendingBackup(userId);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index cb4cac916f65..1f9362e246b7 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1024,7 +1024,8 @@ public final class OomAdjuster {
app.hasStartedServices = false;
app.adjSeq = mAdjSeq;
- if (mService.mBackupTarget != null && app == mService.mBackupTarget.app) {
+ final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId);
+ if (backupTarget != null && app == backupTarget.app) {
// If possible we want to avoid killing apps while they're being backed up
if (adj > ProcessList.BACKUP_APP_ADJ) {
if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 8d7811fc8e78..714a807da1b0 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -1454,8 +1454,8 @@ final class HistoricalRegistry {
if (accessCount > 0) {
if (!printedUidState) {
mWriter.print(mUidStatePrefix);
- mWriter.print(AppOpsManager.uidStateToString(uidState));
- mWriter.print("[");
+ mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+ mWriter.print(" = ");
printedUidState = true;
}
mWriter.print("access=");
@@ -1465,11 +1465,11 @@ final class HistoricalRegistry {
if (rejectCount > 0) {
if (!printedUidState) {
mWriter.print(mUidStatePrefix);
- mWriter.print(AppOpsManager.uidStateToString(uidState));
- mWriter.print("[");
+ mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+ mWriter.print(" = ");
printedUidState = true;
} else {
- mWriter.print(",");
+ mWriter.print(", ");
}
mWriter.print("reject=");
mWriter.print(rejectCount);
@@ -1478,16 +1478,17 @@ final class HistoricalRegistry {
if (accessDuration > 0) {
if (!printedUidState) {
mWriter.print(mUidStatePrefix);
- mWriter.print(AppOpsManager.uidStateToString(uidState));
+ mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+ mWriter.print(" = ");
printedUidState = true;
} else {
- mWriter.print(",");
+ mWriter.print(", ");
}
mWriter.print("duration=");
- mWriter.print(accessDuration);
+ TimeUtils.formatDuration(accessDuration, mWriter);
}
if (printedUidState) {
- mWriter.println("]");
+ mWriter.println("");
}
}
}
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index b332c47ce281..2fe17d8f3c98 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -34,8 +34,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.display.ColorDisplayManager;
+import android.graphics.ColorSpace;
import android.hardware.display.IColorDisplayManager;
import android.net.Uri;
import android.opengl.Matrix;
@@ -59,6 +61,7 @@ import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
import com.android.server.twilight.TwilightState;
+import java.io.PrintWriter;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -148,26 +151,204 @@ public final class ColorDisplayService extends SystemService {
};
private final TintController mDisplayWhiteBalanceTintController = new TintController() {
-
+ // Three chromaticity coordinates per color: X, Y, and Z
+ private final int NUM_VALUES_PER_PRIMARY = 3;
+ // Four colors: red, green, blue, and white
+ private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY;
+
+ private final Object mLock = new Object();
+ private int mTemperatureMin;
+ private int mTemperatureMax;
+ private int mTemperatureDefault;
+ private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ private ColorSpace.Rgb mDisplayColorSpaceRGB;
+ private float[] mChromaticAdaptationMatrix;
+ private int mCurrentColorTemperature;
+ private float[] mCurrentColorTemperatureXYZ;
+ private boolean mSetUp = false;
private float[] mMatrixDisplayWhiteBalance = new float[16];
@Override
public void setUp(Context context, boolean needsLinear) {
+ mSetUp = false;
+
+ final Resources res = getContext().getResources();
+ final String[] displayPrimariesValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayPrimaries);
+ final String[] nominalWhiteValues = res.getStringArray(
+ R.array.config_displayWhiteBalanceDisplayNominalWhite);
+
+ if (displayPrimariesValues.length != NUM_DISPLAY_PRIMARIES_VALS) {
+ Slog.e(TAG, "Unexpected display white balance primaries resource length " +
+ displayPrimariesValues.length);
+ return;
+ }
+
+ if (nominalWhiteValues.length != NUM_VALUES_PER_PRIMARY) {
+ Slog.e(TAG, "Unexpected display white balance nominal white resource length " +
+ nominalWhiteValues.length);
+ return;
+ }
+
+ float[] displayRedGreenBlueXYZ =
+ new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY];
+ float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) {
+ displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]);
+ }
+ for (int i = 0; i < displayWhiteXYZ.length; i++) {
+ displayWhiteXYZ[i] = Float.parseFloat(
+ displayPrimariesValues[displayRedGreenBlueXYZ.length + i]);
+ }
+
+ final ColorSpace.Rgb displayColorSpaceRGB = new ColorSpace.Rgb(
+ "Display Color Space",
+ displayRedGreenBlueXYZ,
+ displayWhiteXYZ,
+ 2.2f // gamma, unused for display white balance
+ );
+
+ float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY];
+ for (int i = 0; i < nominalWhiteValues.length; i++) {
+ displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]);
+ }
+
+ final int colorTemperatureMin = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMin);
+ if (colorTemperatureMin <= 0) {
+ Slog.e(TAG, "display white balance minimum temperature must be greater than 0");
+ return;
+ }
+
+ final int colorTemperatureMax = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureMax);
+ if (colorTemperatureMax < colorTemperatureMin) {
+ Slog.e(TAG, "display white balance max temp must be greater or equal to min");
+ return;
+ }
+
+ final int colorTemperature = res.getInteger(
+ R.integer.config_displayWhiteBalanceColorTemperatureDefault);
+
+ synchronized (mLock) {
+ mDisplayColorSpaceRGB = displayColorSpaceRGB;
+ mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ;
+ mTemperatureMin = colorTemperatureMin;
+ mTemperatureMax = colorTemperatureMax;
+ mTemperatureDefault = colorTemperature;
+ mSetUp = true;
+ }
+
+ setMatrix(mTemperatureDefault);
}
@Override
public float[] getMatrix() {
- return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
+ return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY;
}
@Override
public void setMatrix(int cct) {
+ if (!mSetUp) {
+ Slog.w(TAG, "Can't set display white balance temperature: uninitialized");
+ return;
+ }
+
+ if (cct < mTemperatureMin) {
+ Slog.w(TAG, "Requested display color temperature is below allowed minimum");
+ cct = mTemperatureMin;
+ } else if (cct > mTemperatureMax) {
+ Slog.w(TAG, "Requested display color temperature is above allowed maximum");
+ cct = mTemperatureMax;
+ }
+
+ Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct);
+
+ synchronized (mLock) {
+ mCurrentColorTemperature = cct;
+
+ // Adapt the display's nominal white point to match the requested CCT value
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+
+ mChromaticAdaptationMatrix =
+ ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
+ mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ);
+
+ // Convert the adaptation matrix to RGB space
+ float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix,
+ mDisplayColorSpaceRGB.getTransform());
+ result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result);
+
+ // Normalize the transform matrix to peak white value in RGB space
+ final float adaptedMaxR = result[0] + result[3] + result[6];
+ final float adaptedMaxG = result[1] + result[4] + result[7];
+ final float adaptedMaxB = result[2] + result[5] + result[8];
+ final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB);
+ for (int i = 0; i < result.length; i++) {
+ result[i] /= denum;
+ }
+
+ Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0);
+ java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3);
+ java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3);
+ java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3);
+ }
}
@Override
public int getLevel() {
return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE;
}
+
+ /**
+ * Format a given matrix into a string.
+ *
+ * @param matrix the matrix to format
+ * @param cols number of columns in the matrix
+ */
+ private String matrixToString(float[] matrix, int cols) {
+ if (matrix == null || cols <= 0) {
+ Slog.e(TAG, "Invalid arguments when formatting matrix to string");
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder("");
+ for (int i = 0; i < matrix.length; i++) {
+ if (i % cols == 0) {
+ sb.append("\n ");
+ }
+ sb.append(String.format("%9.6f ", matrix[i]));
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println("ColorDisplayService");
+ pw.println(" mSetUp = " + mSetUp);
+
+ if (!mSetUp) {
+ return;
+ }
+
+ pw.println(" isActivated = " + isActivated());
+ pw.println(" mTemperatureMin = " + mTemperatureMin);
+ pw.println(" mTemperatureMax = " + mTemperatureMax);
+ pw.println(" mTemperatureDefault = " + mTemperatureDefault);
+ pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature);
+ pw.println(" mCurrentColorTemperatureXYZ = " +
+ matrixToString(mCurrentColorTemperatureXYZ, 3));
+ pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " +
+ matrixToString(mDisplayColorSpaceRGB.getTransform(), 3));
+ pw.println(" mChromaticAdaptationMatrix = " +
+ matrixToString(mChromaticAdaptationMatrix, 3));
+ pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " +
+ matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
+ pw.println(" mMatrixDisplayWhiteBalance = " +
+ matrixToString(mMatrixDisplayWhiteBalance, 4));
+ }
+ }
};
private final TintController mGlobalSaturationTintController = new TintController() {
@@ -230,8 +411,6 @@ public final class ColorDisplayService extends SystemService {
private NightDisplayAutoMode mNightDisplayAutoMode;
- private Integer mDisplayWhiteBalanceColorTemperature;
-
public ColorDisplayService(Context context) {
super(context);
mHandler = new TintHandler(Looper.getMainLooper());
@@ -363,7 +542,7 @@ public final class ColorDisplayService extends SystemService {
onAccessibilityTransformChanged();
break;
case Secure.DISPLAY_WHITE_BALANCE_ENABLED:
- onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+ updateDisplayWhiteBalanceStatus();
break;
}
}
@@ -416,14 +595,9 @@ public final class ColorDisplayService extends SystemService {
if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) {
// Prepare the display white balance transform matrix.
- mDisplayWhiteBalanceTintController
- .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix());
- if (mDisplayWhiteBalanceColorTemperature != null) {
- mDisplayWhiteBalanceTintController
- .setMatrix(mDisplayWhiteBalanceColorTemperature);
- }
+ mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */);
- onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled());
+ updateDisplayWhiteBalanceStatus();
}
}
@@ -460,6 +634,8 @@ public final class ColorDisplayService extends SystemService {
mNightDisplayAutoMode.onActivated(activated);
}
+ updateDisplayWhiteBalanceStatus();
+
applyTint(mNightDisplayTintController, false);
}
}
@@ -516,11 +692,7 @@ public final class ColorDisplayService extends SystemService {
.setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature());
- mDisplayWhiteBalanceTintController
- .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode));
- if (mDisplayWhiteBalanceColorTemperature != null) {
- mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature);
- }
+ updateDisplayWhiteBalanceStatus();
final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
dtm.setColorMode(mode, mNightDisplayTintController.getMatrix());
@@ -611,10 +783,15 @@ public final class ColorDisplayService extends SystemService {
return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt;
}
- private void onDisplayWhiteBalanceEnabled(boolean enabled) {
- mDisplayWhiteBalanceTintController.setActivated(enabled);
- if (mDisplayWhiteBalanceListener != null) {
- mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled);
+ private void updateDisplayWhiteBalanceStatus() {
+ boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated();
+ mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() &&
+ !mNightDisplayTintController.isActivated() &&
+ DisplayTransformManager.needsLinearColorMatrix());
+ boolean activated = mDisplayWhiteBalanceTintController.isActivated();
+
+ if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
+ mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated);
}
}
@@ -896,6 +1073,12 @@ public final class ColorDisplayService extends SystemService {
}
/**
+ * Dump debug information.
+ */
+ public void dump(PrintWriter pw) {
+ }
+
+ /**
* Set up any constants needed for computing the matrix.
*/
public abstract void setUp(Context context, boolean needsLinear);
@@ -929,11 +1112,10 @@ public final class ColorDisplayService extends SystemService {
*/
public boolean setDisplayWhiteBalanceColorTemperature(int cct) {
// Update the transform matrix even if it can't be applied.
- mDisplayWhiteBalanceColorTemperature = cct;
mDisplayWhiteBalanceTintController.setMatrix(cct);
if (mDisplayWhiteBalanceTintController.isActivated()) {
- applyTint(mDisplayWhiteBalanceTintController, true);
+ applyTint(mDisplayWhiteBalanceTintController, false);
return true;
}
return false;
@@ -946,6 +1128,10 @@ public final class ColorDisplayService extends SystemService {
mDisplayWhiteBalanceListener = listener;
return mDisplayWhiteBalanceTintController.isActivated();
}
+
+ public void dump(PrintWriter pw) {
+ mDisplayWhiteBalanceTintController.dump(pw);
+ }
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 4a17c6591449..2340b77c4a3c 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -95,6 +95,7 @@ import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1459,6 +1460,13 @@ public final class DisplayManagerService extends SystemService {
pw.println();
mPersistentDataStore.dump(pw);
+
+ final ColorDisplayServiceInternal cds = LocalServices.getService(
+ ColorDisplayServiceInternal.class);
+ if (cds != null) {
+ pw.println();
+ cds.dump(pw);
+ }
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 5fa3f52c6302..7ff6a2fc5574 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -89,6 +89,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks;
@@ -309,6 +310,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private final HardKeyboardListener mHardKeyboardListener;
private final AppOpsManager mAppOpsManager;
private final UserManager mUserManager;
+ private final UserManagerInternal mUserManagerInternal;
// All known input methods. mMethodMap also serves as the global
// lock for this class.
@@ -1405,6 +1407,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}, true /*asyncHandler*/);
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
+ mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
mHardKeyboardListener = new HardKeyboardListener();
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
@@ -1489,7 +1492,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// If the system is not ready or the device is not yed unlocked by the user, then we use
// copy-on-write settings.
final boolean useCopyOnWriteSettings =
- !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId);
+ !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId);
mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings);
updateCurrentProfileIds();
// Additional subtypes should be reset when the user is changed
@@ -1562,7 +1565,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mLastSystemLocales = mRes.getConfiguration().getLocales();
final int currentUserId = mSettings.getCurrentUserId();
mSettings.switchCurrentUser(currentUserId,
- !mUserManager.isUserUnlockingOrUnlocked(currentUserId));
+ !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId));
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
mNotificationManager = mContext.getSystemService(NotificationManager.class);
mStatusBar = statusBar;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index eb3017db7340..b6dae1977262 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -304,6 +304,17 @@ public class LauncherAppsService extends SystemService {
}
@Override
+ public boolean shouldHideFromSuggestions(String packageName, UserHandle user) {
+ if (!canAccessProfile(user.getIdentifier(), "cannot get shouldHideFromSuggestions")) {
+ return false;
+ }
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ int flags = pmi.getDistractingPackageRestrictions(packageName, user.getIdentifier());
+ return (flags & PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS) != 0;
+ }
+
+ @Override
public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
String packageName, UserHandle user) throws RemoteException {
ParceledListSlice<ResolveInfo> launcherActivities = queryActivitiesForUser(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 597f5b3f4e05..945d7ad008d4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -84,6 +84,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
@@ -12657,22 +12658,30 @@ public class PackageManagerService extends IPackageManager.Stub
info.sendPackageRemovedBroadcasts(true /*killApp*/);
}
+ private void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId,
+ int distractionFlags) {
+ final Bundle extras = new Bundle(3);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, distractionFlags);
+ sendPackageBroadcast(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED, null, extras,
+ Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null, new int[]{userId}, null);
+ }
+
private void sendPackagesSuspendedForUser(String[] pkgList, int[] uidList, int userId,
boolean suspended, PersistableBundle launcherExtras) {
- if (pkgList.length > 0) {
- Bundle extras = new Bundle(1);
- extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
- extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
- if (launcherExtras != null) {
- extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS,
- new Bundle(launcherExtras.deepCopy()));
- }
- sendPackageBroadcast(
- suspended ? Intent.ACTION_PACKAGES_SUSPENDED
- : Intent.ACTION_PACKAGES_UNSUSPENDED,
- null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
- new int[] {userId}, null);
+ final Bundle extras = new Bundle(3);
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
+ extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidList);
+ if (launcherExtras != null) {
+ extras.putBundle(Intent.EXTRA_LAUNCHER_EXTRAS,
+ new Bundle(launcherExtras.deepCopy()));
}
+ sendPackageBroadcast(
+ suspended ? Intent.ACTION_PACKAGES_SUSPENDED
+ : Intent.ACTION_PACKAGES_UNSUSPENDED,
+ null, extras, Intent.FLAG_RECEIVER_REGISTERED_ONLY, null, null,
+ new int[] {userId}, null);
}
/**
@@ -12822,6 +12831,62 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
+ int restrictionFlags, int userId) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS,
+ "setPackagesSuspendedAsUser");
+
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
+ && UserHandle.getUserId(callingUid) != userId) {
+ throw new SecurityException("Calling uid " + callingUid + " cannot call for user "
+ + userId);
+ }
+ Preconditions.checkNotNull(packageNames, "packageNames cannot be null");
+
+ final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
+ final IntArray changedUids = new IntArray(packageNames.length);
+ final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
+
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ final PackageSetting pkgSetting;
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ Slog.w(TAG, "Could not find package setting for package: " + packageName
+ + ". Skipping...");
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ }
+ if (restrictionFlags != 0 && !canSuspendPackageForUserInternal(packageName, userId)) {
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ synchronized (mPackages) {
+ final int oldDistractionFlags = pkgSetting.getDistractionFlags(userId);
+ if (restrictionFlags != oldDistractionFlags) {
+ pkgSetting.setDistractionFlags(restrictionFlags, userId);
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
+ }
+ }
+ }
+
+ if (!changedPackagesList.isEmpty()) {
+ final String[] changedPackages = changedPackagesList.toArray(
+ new String[changedPackagesList.size()]);
+ sendDistractingPackagesChanged(changedPackages, changedUids.toArray(), userId,
+ restrictionFlags);
+ synchronized (mPackages) {
+ scheduleWritePackageRestrictionsLocked(userId);
+ }
+ }
+ return unactionedPackages.toArray(new String[0]);
+ }
+
+ @Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
SuspendDialogInfo dialogInfo, String callingPackage, int userId) {
@@ -12846,44 +12911,37 @@ public class PackageManagerService extends IPackageManager.Stub
final List<String> changedPackagesList = new ArrayList<>(packageNames.length);
final IntArray changedUids = new IntArray(packageNames.length);
final List<String> unactionedPackages = new ArrayList<>(packageNames.length);
- final long callingId = Binder.clearCallingIdentity();
- try {
- for (int i = 0; i < packageNames.length; i++) {
- final String packageName = packageNames[i];
- if (callingPackage.equals(packageName)) {
- Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
- + (suspended ? "" : "un") + "suspend itself. Ignoring");
- unactionedPackages.add(packageName);
- continue;
- }
- PackageSetting pkgSetting;
- synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting == null
- || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
- Slog.w(TAG, "Could not find package setting for package: " + packageName
- + ". Skipping suspending/un-suspending.");
- unactionedPackages.add(packageName);
- continue;
- }
- }
- if (suspended && !canSuspendPackageForUserInternal(packageName, userId)) {
+
+ for (int i = 0; i < packageNames.length; i++) {
+ final String packageName = packageNames[i];
+ if (callingPackage.equals(packageName)) {
+ Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ + (suspended ? "" : "un") + "suspend itself. Ignoring");
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ final PackageSetting pkgSetting;
+ synchronized (mPackages) {
+ pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null || filterAppAccessLPr(pkgSetting, callingUid, userId)) {
+ Slog.w(TAG, "Could not find package setting for package: " + packageName
+ + ". Skipping suspending/un-suspending.");
unactionedPackages.add(packageName);
continue;
}
- synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
- if (pkgSetting != null) {
- pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
- launcherExtras, userId);
- }
- }
- changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
- } finally {
- Binder.restoreCallingIdentity(callingId);
+ if (suspended && !canSuspendPackageForUserInternal(packageName, userId)) {
+ unactionedPackages.add(packageName);
+ continue;
+ }
+ synchronized (mPackages) {
+ pkgSetting.setSuspended(suspended, callingPackage, dialogInfo, appExtras,
+ launcherExtras, userId);
+ }
+ changedPackagesList.add(packageName);
+ changedUids.add(UserHandle.getUid(userId, pkgSetting.appId));
}
+
if (!changedPackagesList.isEmpty()) {
final String[] changedPackages = changedPackagesList.toArray(
new String[changedPackagesList.size()]);
@@ -13035,88 +13093,87 @@ public class PackageManagerService extends IPackageManager.Stub
+ " cannot query getUnsuspendablePackagesForUser for user " + userId);
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final long identity = Binder.clearCallingIdentity();
- try {
- for (String packageName : packageNames) {
- if (!canSuspendPackageForUserInternal(packageName, userId)) {
- unactionablePackages.add(packageName);
- }
+ for (String packageName : packageNames) {
+ if (!canSuspendPackageForUserInternal(packageName, userId)) {
+ unactionablePackages.add(packageName);
}
- } finally {
- Binder.restoreCallingIdentity(identity);
}
return unactionablePackages.toArray(new String[unactionablePackages.size()]);
}
private boolean canSuspendPackageForUserInternal(String packageName, int userId) {
- if (isPackageDeviceAdmin(packageName, userId)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": has an active device admin");
- return false;
- }
-
- String activeLauncherPackageName = getActiveLauncherPackageName(userId);
- if (packageName.equals(activeLauncherPackageName)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": contains the active launcher");
- return false;
- }
-
- if (packageName.equals(mRequiredInstallerPackage)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": required for package installation");
- return false;
- }
+ final long callingId = Binder.clearCallingIdentity();
+ try {
+ if (isPackageDeviceAdmin(packageName, userId)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": has an active device admin");
+ return false;
+ }
- if (packageName.equals(mRequiredUninstallerPackage)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": required for package uninstallation");
- return false;
- }
+ String activeLauncherPackageName = getActiveLauncherPackageName(userId);
+ if (packageName.equals(activeLauncherPackageName)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": contains the active launcher");
+ return false;
+ }
- if (packageName.equals(mRequiredVerifierPackage)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": required for package verification");
- return false;
- }
+ if (packageName.equals(mRequiredInstallerPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for package installation");
+ return false;
+ }
- if (packageName.equals(getDefaultDialerPackageName(userId))) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": is the default dialer");
- return false;
- }
+ if (packageName.equals(mRequiredUninstallerPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for package uninstallation");
+ return false;
+ }
- if (packageName.equals(mRequiredPermissionControllerPackage)) {
- Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": required for permissions management");
- return false;
- }
+ if (packageName.equals(mRequiredVerifierPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for package verification");
+ return false;
+ }
- synchronized (mPackages) {
- if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ if (packageName.equals(getDefaultDialerPackageName(userId))) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
- + "\": protected package");
+ + "\": is the default dialer");
return false;
}
- // Cannot suspend static shared libs as they are considered
- // a part of the using app (emulating static linking). Also
- // static libs are installed always on internal storage.
- PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
- Slog.w(TAG, "Cannot suspend package: " + packageName
- + " providing static shared library: "
- + pkg.staticSharedLibName);
+ if (packageName.equals(mRequiredPermissionControllerPackage)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": required for permissions management");
return false;
}
- }
- if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
- Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
- return false;
- }
+ synchronized (mPackages) {
+ if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
+ Slog.w(TAG, "Cannot suspend package \"" + packageName
+ + "\": protected package");
+ return false;
+ }
- return true;
+ // Cannot suspend static shared libs as they are considered
+ // a part of the using app (emulating static linking). Also
+ // static libs are installed always on internal storage.
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg != null && pkg.applicationInfo.isStaticSharedLibrary()) {
+ Slog.w(TAG, "Cannot suspend package: " + packageName
+ + " providing static shared library: "
+ + pkg.staticSharedLibName);
+ return false;
+ }
+ }
+
+ if (PLATFORM_PACKAGE_NAME.equals(packageName)) {
+ Slog.w(TAG, "Cannot suspend the platform package: " + packageName);
+ return false;
+ }
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(callingId);
+ }
}
private String getActiveLauncherPackageName(int userId) {
@@ -13717,14 +13774,15 @@ public class PackageManagerService extends IPackageManager.Stub
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
+ int userId = args.user.getIdentifier();
if (DEBUG_INSTALL) {
- Log.v(TAG, "token " + token + " to BM for possible restore");
+ Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
}
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
try {
- // TODO: http://b/22388012
- if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
- bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
+ if (bm.isBackupServiceActive(userId)) {
+ bm.restoreAtInstallForUser(
+ userId, res.pkg.applicationInfo.packageName, token);
} else {
doRestore = false;
}
@@ -18425,6 +18483,7 @@ public class PackageManagerService extends IPackageManager.Stub
true /*stopped*/,
true /*notLaunched*/,
false /*hidden*/,
+ 0 /*distractionFlags*/,
false /*suspended*/,
null /*suspendingPackage*/,
null /*dialogInfo*/,
@@ -23240,6 +23299,14 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public int getDistractingPackageRestrictions(String packageName, int userId) {
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ return (ps != null) ? ps.getDistractionFlags(userId) : RESTRICTION_NONE;
+ }
+ }
+
+ @Override
public int getPackageUid(String packageName, int flags, int userId) {
return PackageManagerService.this
.getPackageUid(packageName, flags, userId);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 3c22f07ad108..58f262c4c889 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -392,6 +392,14 @@ public abstract class PackageSettingBase extends SettingBase {
modifyUserState(userId).hidden = hidden;
}
+ int getDistractionFlags(int userId) {
+ return readUserState(userId).distractionFlags;
+ }
+
+ void setDistractionFlags(int distractionFlags, int userId) {
+ modifyUserState(userId).distractionFlags = distractionFlags;
+ }
+
boolean getSuspended(int userId) {
return readUserState(userId).suspended;
}
@@ -423,7 +431,8 @@ public abstract class PackageSettingBase extends SettingBase {
}
void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
- boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
+ boolean notLaunched, boolean hidden, int distractionFlags, boolean suspended,
+ String suspendingPackage,
SuspendDialogInfo dialogInfo, PersistableBundle suspendedAppExtras,
PersistableBundle suspendedLauncherExtras, boolean instantApp,
boolean virtualPreload, String lastDisableAppCaller,
@@ -437,6 +446,7 @@ public abstract class PackageSettingBase extends SettingBase {
state.stopped = stopped;
state.notLaunched = notLaunched;
state.hidden = hidden;
+ state.distractionFlags = distractionFlags;
state.suspended = suspended;
state.suspendingPackage = suspendingPackage;
state.dialogInfo = dialogInfo;
@@ -607,6 +617,7 @@ public abstract class PackageSettingBase extends SettingBase {
}
proto.write(PackageProto.UserInfoProto.INSTALL_TYPE, installType);
proto.write(PackageProto.UserInfoProto.IS_HIDDEN, state.hidden);
+ proto.write(PackageProto.UserInfoProto.DISTRACTION_FLAGS, state.distractionFlags);
proto.write(PackageProto.UserInfoProto.IS_SUSPENDED, state.suspended);
if (state.suspended) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE, state.suspendingPackage);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index c524dba01ba6..95da2091828d 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -223,6 +223,7 @@ public final class Settings {
private static final String ATTR_BLOCKED = "blocked";
// New name for the above attribute.
private static final String ATTR_HIDDEN = "hidden";
+ private static final String ATTR_DISTRACTION_FLAGS = "distraction_flags";
private static final String ATTR_SUSPENDED = "suspended";
private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
/**
@@ -734,6 +735,7 @@ public final class Settings {
true /*stopped*/,
true /*notLaunched*/,
false /*hidden*/,
+ 0 /*distractionFlags*/,
false /*suspended*/,
null /*suspendingPackage*/,
null /*dialogInfo*/,
@@ -1628,6 +1630,7 @@ public final class Settings {
false /*stopped*/,
false /*notLaunched*/,
false /*hidden*/,
+ 0 /*distractionFlags*/,
false /*suspended*/,
null /*suspendingPackage*/,
null /*dialogInfo*/,
@@ -1703,6 +1706,8 @@ public final class Settings {
hidden = hiddenStr == null
? hidden : Boolean.parseBoolean(hiddenStr);
+ final int distractionFlags = XmlUtils.readIntAttribute(parser,
+ ATTR_DISTRACTION_FLAGS, 0);
final boolean suspended = XmlUtils.readBooleanAttribute(parser, ATTR_SUSPENDED,
false);
String suspendingPackage = parser.getAttributeValue(null,
@@ -1781,7 +1786,8 @@ public final class Settings {
setBlockUninstallLPw(userId, name, true);
}
ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
- hidden, suspended, suspendingPackage, suspendDialogInfo,
+ hidden, distractionFlags, suspended, suspendingPackage,
+ suspendDialogInfo,
suspendedAppExtras, suspendedLauncherExtras, instantApp, virtualPreload,
enabledCaller, enabledComponents, disabledComponents, verifState,
linkGeneration, installReason, harmfulAppWarning);
@@ -2089,6 +2095,10 @@ public final class Settings {
if (ustate.hidden) {
serializer.attribute(null, ATTR_HIDDEN, "true");
}
+ if (ustate.distractionFlags != 0) {
+ serializer.attribute(null, ATTR_DISTRACTION_FLAGS,
+ Integer.toString(ustate.distractionFlags));
+ }
if (ustate.suspended) {
serializer.attribute(null, ATTR_SUSPENDED, "true");
if (ustate.suspendingPackage != null) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index ac05ee8a9779..bd14223c962c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -130,7 +130,7 @@ public class StagingManager {
ServiceManager.getService("apexservice"));
boolean success;
try {
- success = apex.submitStagedSession(sessionId, apexInfoList);
+ success = apex.submitStagedSession(sessionId, new int[0], apexInfoList);
} catch (RemoteException re) {
Slog.e(TAG, "Unable to contact apexservice", re);
return false;
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index b4883371b468..c0ec3672c665 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -406,7 +406,6 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Nullable
private ArraySet<String> getRoleHoldersInternal(@NonNull String roleName,
@UserIdInt int userId) {
- migrateRoleIfNecessary(roleName, userId);
RoleUserState userState = getOrCreateUserState(userId);
return userState.getRoleHolders(roleName);
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 80212655d616..d12f7eda9a1b 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -977,6 +977,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
ensureRollbackDataLoadedLocked();
mAvailableRollbacks.add(data);
}
+
+ scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
} catch (IOException e) {
Log.e(TAG, "Unable to enable rollback", e);
removeFile(data.backupDir);
diff --git a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
index 438c303de6cc..d77cf900a0a9 100644
--- a/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
+++ b/services/core/java/com/android/server/signedconfig/GlobalSettingsConfigApplicator.java
@@ -23,6 +23,7 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import android.util.StatsLog;
import java.security.GeneralSecurityException;
import java.util.Arrays;
@@ -66,12 +67,14 @@ class GlobalSettingsConfigApplicator {
private final Context mContext;
private final String mSourcePackage;
+ private final SignedConfigEvent mEvent;
private final SignatureVerifier mVerifier;
- GlobalSettingsConfigApplicator(Context context, String sourcePackage) {
+ GlobalSettingsConfigApplicator(Context context, String sourcePackage, SignedConfigEvent event) {
mContext = context;
mSourcePackage = sourcePackage;
- mVerifier = new SignatureVerifier();
+ mEvent = event;
+ mVerifier = new SignatureVerifier(mEvent);
}
private boolean checkSignature(String data, String signature) {
@@ -79,6 +82,7 @@ class GlobalSettingsConfigApplicator {
return mVerifier.verifySignature(data, signature);
} catch (GeneralSecurityException e) {
Slog.e(TAG, "Failed to verify signature", e);
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SECURITY_EXCEPTION;
return false;
}
}
@@ -109,14 +113,17 @@ class GlobalSettingsConfigApplicator {
SignedConfig config;
try {
config = SignedConfig.parse(configStr, ALLOWED_KEYS, KEY_VALUE_MAPPERS);
+ mEvent.version = config.version;
} catch (InvalidConfigException e) {
Slog.e(TAG, "Failed to parse global settings from package " + mSourcePackage, e);
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__INVALID_CONFIG;
return;
}
int currentVersion = getCurrentConfigVersion();
if (currentVersion >= config.version) {
Slog.i(TAG, "Global settings from package " + mSourcePackage
+ " is older than existing: " + config.version + "<=" + currentVersion);
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__OLD_CONFIG;
return;
}
// We have new config!
@@ -126,10 +133,12 @@ class GlobalSettingsConfigApplicator {
config.getMatchingConfig(Build.VERSION.SDK_INT);
if (matchedConfig == null) {
Slog.i(TAG, "Settings is not applicable to current SDK version; ignoring");
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__NOT_APPLICABLE;
return;
}
Slog.i(TAG, "Updating global settings to version " + config.version);
updateCurrentConfig(config.version, matchedConfig.values);
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__APPLIED;
}
}
diff --git a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
index 944db84acc71..56db32a3071d 100644
--- a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
+++ b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java
@@ -18,6 +18,7 @@ package com.android.server.signedconfig;
import android.os.Build;
import android.util.Slog;
+import android.util.StatsLog;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
@@ -42,11 +43,18 @@ public class SignatureVerifier {
private static final String DEBUG_KEY =
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaAn2XVifsLTHg616nTsOMVmlhBoECGbTEBTKKvdd2hO60"
+ "pj1pnU8SMkhYfaNxZuKgw9LNvOwlFwStboIYeZ3lQ==";
+ private static final String PROD_KEY =
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+lky6wKyGL6lE1VrD0YTMHwb0Xwc+tzC8MvnrzVxodvTp"
+ + "VY/jV7V+Zktcx+pry43XPABFRXtbhTo+qykhyBA1g==";
+ private final SignedConfigEvent mEvent;
private final PublicKey mDebugKey;
+ private final PublicKey mProdKey;
- public SignatureVerifier() {
- mDebugKey = createKey(DEBUG_KEY);
+ public SignatureVerifier(SignedConfigEvent event) {
+ mEvent = event;
+ mDebugKey = Build.IS_DEBUGGABLE ? createKey(DEBUG_KEY) : null;
+ mProdKey = createKey(PROD_KEY);
}
private static PublicKey createKey(String base64) {
@@ -67,6 +75,14 @@ public class SignatureVerifier {
}
}
+ private boolean verifyWithPublicKey(PublicKey key, byte[] data, byte[] signature)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ Signature verifier = Signature.getInstance("SHA256withECDSA");
+ verifier.initVerify(key);
+ verifier.update(data);
+ return verifier.verify(signature);
+ }
+
/**
* Verify a signature for signed config.
*
@@ -80,6 +96,7 @@ public class SignatureVerifier {
try {
signature = Base64.getDecoder().decode(base64Signature);
} catch (IllegalArgumentException e) {
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_SIGNATURE;
Slog.e(TAG, "Failed to base64 decode signature");
return false;
}
@@ -89,11 +106,9 @@ public class SignatureVerifier {
if (Build.IS_DEBUGGABLE) {
if (mDebugKey != null) {
if (DBG) Slog.w(TAG, "Trying to verify signature using debug key");
- Signature verifier = Signature.getInstance("SHA256withECDSA");
- verifier.initVerify(mDebugKey);
- verifier.update(data);
- if (verifier.verify(signature)) {
+ if (verifyWithPublicKey(mDebugKey, data, signature)) {
Slog.i(TAG, "Verified config using debug key");
+ mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__DEBUG;
return true;
} else {
if (DBG) Slog.i(TAG, "Config verification failed using debug key");
@@ -102,8 +117,20 @@ public class SignatureVerifier {
Slog.w(TAG, "Debuggable build, but have no debug key");
}
}
- // TODO verify production key.
- Slog.w(TAG, "NO PRODUCTION KEY YET, FAILING VERIFICATION");
- return false;
+ if (mProdKey == null) {
+ Slog.e(TAG, "No prod key; construction failed?");
+ mEvent.status =
+ StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT;
+ return false;
+ }
+ if (verifyWithPublicKey(mProdKey, data, signature)) {
+ Slog.i(TAG, "Verified config using production key");
+ mEvent.verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__PRODUCTION;
+ return true;
+ } else {
+ if (DBG) Slog.i(TAG, "Verification failed using production key");
+ mEvent.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED;
+ return false;
+ }
}
}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java
new file mode 100644
index 000000000000..2f2062c6f2ee
--- /dev/null
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigEvent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.signedconfig;
+
+import android.util.StatsLog;
+
+/**
+ * Helper class to allow a SignedConfigReported event to be built up in stages.
+ */
+public class SignedConfigEvent {
+
+ public int type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__UNKNOWN_TYPE;
+ public int status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__UNKNOWN_STATUS;
+ public int version = 0;
+ public String fromPackage = null;
+ public int verifiedWith = StatsLog.SIGNED_CONFIG_REPORTED__VERIFIED_WITH__NO_KEY;
+
+ /**
+ * Write this event to statslog.
+ */
+ public void send() {
+ StatsLog.write(StatsLog.SIGNED_CONFIG_REPORTED,
+ type, status, version, fromPackage, verifiedWith);
+ }
+
+}
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
index 6bcee1413fa8..dc39542dc29f 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
@@ -26,6 +26,7 @@ import android.content.pm.PackageManagerInternal;
import android.net.Uri;
import android.os.Bundle;
import android.util.Slog;
+import android.util.StatsLog;
import com.android.server.LocalServices;
@@ -82,21 +83,30 @@ public class SignedConfigService {
}
if (metaData.containsKey(KEY_GLOBAL_SETTINGS)
&& metaData.containsKey(KEY_GLOBAL_SETTINGS_SIGNATURE)) {
- String config = metaData.getString(KEY_GLOBAL_SETTINGS);
- String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
+ SignedConfigEvent event = new SignedConfigEvent();
try {
- // Base64 encoding is standard (not URL safe) encoding: RFC4648
- config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
- } catch (IllegalArgumentException iae) {
- Slog.e(TAG, "Failed to base64 decode global settings config from " + packageName);
- return;
+ event.type = StatsLog.SIGNED_CONFIG_REPORTED__TYPE__GLOBAL_SETTINGS;
+ event.fromPackage = packageName;
+ String config = metaData.getString(KEY_GLOBAL_SETTINGS);
+ String signature = metaData.getString(KEY_GLOBAL_SETTINGS_SIGNATURE);
+ try {
+ // Base64 encoding is standard (not URL safe) encoding: RFC4648
+ config = new String(Base64.getDecoder().decode(config), StandardCharsets.UTF_8);
+ } catch (IllegalArgumentException iae) {
+ Slog.e(TAG, "Failed to base64 decode global settings config from "
+ + packageName);
+ event.status = StatsLog.SIGNED_CONFIG_REPORTED__STATUS__BASE64_FAILURE_CONFIG;
+ return;
+ }
+ if (DBG) {
+ Slog.d(TAG, "Got global settings config: " + config);
+ Slog.d(TAG, "Got global settings signature: " + signature);
+ }
+ new GlobalSettingsConfigApplicator(mContext, packageName, event).applyConfig(
+ config, signature);
+ } finally {
+ event.send();
}
- if (DBG) {
- Slog.d(TAG, "Got global settings config: " + config);
- Slog.d(TAG, "Got global settings signature: " + signature);
- }
- new GlobalSettingsConfigApplicator(mContext, packageName).applyConfig(
- config, signature);
} else {
if (DBG) Slog.d(TAG, "Package has no global settings config/signature.");
}
diff --git a/services/core/java/com/android/server/slice/SlicePermissionManager.java b/services/core/java/com/android/server/slice/SlicePermissionManager.java
index 315d5e39c94b..1d1c28f5f9b7 100644
--- a/services/core/java/com/android/server/slice/SlicePermissionManager.java
+++ b/services/core/java/com/android/server/slice/SlicePermissionManager.java
@@ -175,18 +175,24 @@ public class SlicePermissionManager implements DirtyTracker {
handlePersist();
}
for (String file : new File(mSliceDir.getAbsolutePath()).list()) {
- if (file.isEmpty()) continue;
try (ParserHolder parser = getParser(file)) {
- Persistable p;
- while (parser.parser.getEventType() != XmlPullParser.START_TAG) {
+ Persistable p = null;
+ while (parser.parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ if (parser.parser.getEventType() == XmlPullParser.START_TAG) {
+ if (SliceClientPermissions.TAG_CLIENT.equals(parser.parser.getName())) {
+ p = SliceClientPermissions.createFrom(parser.parser, tracker);
+ } else {
+ p = SliceProviderPermissions.createFrom(parser.parser, tracker);
+ }
+ break;
+ }
parser.parser.next();
}
- if (SliceClientPermissions.TAG_CLIENT.equals(parser.parser.getName())) {
- p = SliceClientPermissions.createFrom(parser.parser, tracker);
+ if (p != null) {
+ p.writeTo(out);
} else {
- p = SliceProviderPermissions.createFrom(parser.parser, tracker);
+ Slog.w(TAG, "Invalid or empty slice permissions file: " + file);
}
- p.writeTo(out);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a207354f6c88..ef3c8d5257fb 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.ActivityManager.START_ABORTED;
import static android.app.ActivityManager.START_CANCELED;
@@ -50,6 +51,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
@@ -745,8 +747,9 @@ class ActivityStarter {
// not sure if we need to create START_ABORTED_BACKGROUND so for now piggybacking
// on START_ABORTED
if (!abort) {
- abort |= shouldAbortBackgroundActivityStart(callingUid, callingPackage, realCallingUid,
- callerApp, originatingPendingIntent, allowBackgroundActivityStart);
+ abort |= shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage,
+ realCallingUid, callerApp, originatingPendingIntent,
+ allowBackgroundActivityStart);
}
// Merge the two options bundles, while realCallerOptions takes precedence.
@@ -893,8 +896,8 @@ class ActivityStarter {
true /* doResume */, checkedOptions, inTask, outActivity);
}
- private boolean shouldAbortBackgroundActivityStart(int callingUid, final String callingPackage,
- int realCallingUid, WindowProcessController callerApp,
+ private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
+ final String callingPackage, int realCallingUid, WindowProcessController callerApp,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
if (mService.isBackgroundActivityStartsEnabled()) {
return false;
@@ -928,6 +931,11 @@ class ActivityStarter {
if (callerApp != null && callerApp.areBackgroundActivityStartsAllowed()) {
return false;
}
+ // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
+ if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
+ == PERMISSION_GRANTED) {
+ return false;
+ }
// don't abort if the caller has the same uid as the recents component
if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
return false;
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index 0d3b6b2afd2c..b8db3f39eb62 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -46,6 +46,7 @@ import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
import com.android.server.backup.testing.TransportData;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBinder;
import org.junit.After;
@@ -65,7 +66,7 @@ import java.io.PrintWriter;
/** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBinder.class})
+@Config(shadows = {ShadowApplicationPackageManager.class, ShadowBinder.class})
@Presubmit
public class BackupManagerServiceTest {
private static final String TEST_PACKAGE = "package";
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 496817613216..3b7fa3d6ed05 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -42,6 +42,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.PowerManager;
@@ -54,6 +56,7 @@ import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.backup.transport.TransportNotRegisteredException;
import com.android.server.testing.shadows.ShadowAppBackupUtils;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBinder;
import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
import com.android.server.testing.shadows.ShadowKeyValueBackupTask;
@@ -80,7 +83,7 @@ import java.util.List;
* UserBackupManagerService} that performs operations for its target user.
*/
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowAppBackupUtils.class})
+@Config(shadows = {ShadowAppBackupUtils.class, ShadowApplicationPackageManager.class})
@Presubmit
public class UserBackupManagerServiceTest {
private static final String TAG = "BMSTest";
@@ -137,6 +140,7 @@ public class UserBackupManagerServiceTest {
public void tearDown() throws Exception {
mBackupThread.quit();
ShadowAppBackupUtils.reset();
+ ShadowApplicationPackageManager.reset();
}
/**
@@ -195,6 +199,7 @@ public class UserBackupManagerServiceTest {
public void testIsAppEligibleForBackup_whenAppNotEligible() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
+ registerPackages(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
boolean result = backupManagerService.isAppEligibleForBackup(PACKAGE_1);
@@ -210,6 +215,7 @@ public class UserBackupManagerServiceTest {
public void testIsAppEligibleForBackup_whenAppEligible() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpCurrentTransport(mTransportManager, backupTransport());
+ registerPackages(PACKAGE_1);
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
@@ -228,6 +234,7 @@ public class UserBackupManagerServiceTest {
public void testIsAppEligibleForBackup_withoutPermission() throws Exception {
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
+ registerPackages(PACKAGE_1);
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
@@ -245,6 +252,7 @@ public class UserBackupManagerServiceTest {
public void testFilterAppsEligibleForBackup() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpCurrentTransport(mTransportManager, mTransport);
+ registerPackages(PACKAGE_1, PACKAGE_2);
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(PACKAGE_1);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
@@ -264,6 +272,7 @@ public class UserBackupManagerServiceTest {
@Test
public void testFilterAppsEligibleForBackup_whenNoneIsEligible() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+ registerPackages(PACKAGE_1, PACKAGE_2);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
String[] filtered =
@@ -281,6 +290,7 @@ public class UserBackupManagerServiceTest {
public void testFilterAppsEligibleForBackup_withoutPermission() throws Exception {
mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
setUpCurrentTransport(mTransportManager, mTransport);
+ registerPackages(PACKAGE_1, PACKAGE_2);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
expectThrows(
@@ -749,7 +759,7 @@ public class UserBackupManagerServiceTest {
private void setUpForRequestBackup(String... packages) throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
for (String packageName : packages) {
- mShadowPackageManager.addPackage(packageName);
+ registerPackages(packageName);
ShadowAppBackupUtils.setAppRunningAndEligibleForBackupWithTransport(packageName);
}
setUpCurrentTransport(mTransportManager, mTransport);
@@ -864,7 +874,7 @@ public class UserBackupManagerServiceTest {
@Test
public void testRequestBackup_whenAppNotEligibleForBackup() throws Exception {
mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
- mShadowPackageManager.addPackage(PACKAGE_1);
+ registerPackages(PACKAGE_1);
setUpCurrentTransport(mTransportManager, mTransport);
UserBackupManagerService backupManagerService = createUserBackupManagerServiceAndRunTasks();
backupManagerService.setEnabled(true);
@@ -1127,6 +1137,22 @@ public class UserBackupManagerServiceTest {
backupManagerService.setPowerManager(powerManagerMock);
}
+ private PackageInfo getPackageInfo(String packageName) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.packageName = packageName;
+ return packageInfo;
+ }
+
+ private void registerPackages(String... packages) {
+ for (String packageName : packages) {
+ PackageInfo packageInfo = getPackageInfo(packageName);
+ mShadowPackageManager.installPackage(packageInfo);
+ ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
+ }
+ }
+
/**
* We can't mock the void method {@link #schedule(Context, long, BackupManagerConstants)} so we
* extend {@link ShadowKeyValueBackupJob} and throw an exception at the end of the method.
diff --git a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
index b08ae6d5756e..bfb2b1479c74 100644
--- a/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/internal/SetupObserverTest.java
@@ -29,6 +29,7 @@ import com.android.server.backup.TransportManager;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.testing.BackupManagerServiceTestUtils;
import com.android.server.backup.testing.TestUtils;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import org.junit.Before;
import org.junit.Test;
@@ -37,6 +38,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
import java.io.File;
@@ -45,6 +47,7 @@ import java.io.File;
* UserBackupManagerService}.
*/
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowApplicationPackageManager.class})
@Presubmit
public class SetupObserverTest {
private static final String TAG = "SetupObserverTest";
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index b923bb09a423..4811523b22f9 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -71,7 +71,6 @@ import static java.util.stream.Collectors.toList;
import android.annotation.Nullable;
import android.app.Application;
-import android.app.ApplicationPackageManager;
import android.app.IBackupAgent;
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
@@ -116,6 +115,7 @@ import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
import com.android.server.testing.shadows.FrameworkShadowLooper;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowBackupDataInput;
import com.android.server.testing.shadows.ShadowBackupDataOutput;
import com.android.server.testing.shadows.ShadowEventLog;
@@ -135,8 +135,6 @@ import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
-import org.robolectric.annotation.Implements;
-import org.robolectric.annotation.Resetter;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.shadows.ShadowPackageManager;
import org.robolectric.shadows.ShadowQueuedWork;
@@ -160,7 +158,7 @@ import java.util.stream.Stream;
@Config(
shadows = {
FrameworkShadowLooper.class,
- KeyValueBackupTaskTest.ShadowApplicationPackageManager.class,
+ ShadowApplicationPackageManager.class,
ShadowBackupDataInput.class,
ShadowBackupDataOutput.class,
ShadowEventLog.class,
@@ -2437,11 +2435,12 @@ public class KeyValueBackupTaskTest {
private AgentMock setUpAgent(PackageData packageData) {
try {
+ String packageName = packageData.packageName;
mPackageManager.setApplicationEnabledSetting(
- packageData.packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+ packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
PackageInfo packageInfo = getPackageInfo(packageData);
mShadowPackageManager.installPackage(packageInfo);
- ShadowApplicationPackageManager.setPackageInfo(packageInfo);
+ ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
mContext.sendBroadcast(getPackageAddedIntent(packageData));
// Run the backup looper because on the receiver we post MSG_SCHEDULE_BACKUP_PACKAGE
mShadowBackupLooper.runToEndOfTasks();
@@ -2537,7 +2536,7 @@ public class KeyValueBackupTaskTest {
private PackageManagerBackupAgent createPmAgent() {
PackageManagerBackupAgent pmAgent =
- new PackageManagerBackupAgent(mApplication.getPackageManager());
+ new PackageManagerBackupAgent(mApplication.getPackageManager(), USER_ID);
pmAgent.attach(mApplication);
pmAgent.onCreate();
return pmAgent;
@@ -2842,7 +2841,7 @@ public class KeyValueBackupTaskTest {
ThrowingPackageManagerBackupAgent(
PackageManager packageManager, RuntimeException exception) {
- super(packageManager);
+ super(packageManager, USER_ID);
mException = exception;
}
@@ -2854,29 +2853,4 @@ public class KeyValueBackupTaskTest {
throw mException;
}
}
-
- /**
- * Extends {@link org.robolectric.shadows.ShadowApplicationPackageManager} to return the correct
- * package in user-specific invocations.
- */
- @Implements(value = ApplicationPackageManager.class)
- public static class ShadowApplicationPackageManager
- extends org.robolectric.shadows.ShadowApplicationPackageManager {
- private static PackageInfo sPackageInfo;
-
- static void setPackageInfo(PackageInfo packageInfo) {
- sPackageInfo = packageInfo;
- }
-
- @Override
- protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) {
- return sPackageInfo;
- }
-
- /** Clear {@link #sPackageInfo}. */
- @Resetter
- public static void reset() {
- sPackageInfo = null;
- }
- }
}
diff --git a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index 4009876314e8..f17a9fe48c61 100644
--- a/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -57,6 +57,7 @@ import com.android.server.backup.internal.BackupHandler;
import com.android.server.backup.testing.TransportData;
import com.android.server.backup.testing.TransportTestUtils;
import com.android.server.backup.testing.TransportTestUtils.TransportMock;
+import com.android.server.testing.shadows.ShadowApplicationPackageManager;
import com.android.server.testing.shadows.ShadowEventLog;
import com.android.server.testing.shadows.ShadowPerformUnifiedRestoreTask;
@@ -77,7 +78,13 @@ import org.robolectric.shadows.ShadowPackageManager;
import java.util.ArrayDeque;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowEventLog.class, ShadowPerformUnifiedRestoreTask.class, ShadowBinder.class})
+@Config(
+ shadows = {
+ ShadowApplicationPackageManager.class,
+ ShadowBinder.class,
+ ShadowEventLog.class,
+ ShadowPerformUnifiedRestoreTask.class
+ })
@Presubmit
public class ActiveRestoreSessionTest {
private static final String PACKAGE_1 = "com.example.package1";
@@ -140,6 +147,7 @@ public class ActiveRestoreSessionTest {
@After
public void tearDown() throws Exception {
+ ShadowApplicationPackageManager.reset();
ShadowPerformUnifiedRestoreTask.reset();
}
@@ -561,7 +569,8 @@ public class ActiveRestoreSessionTest {
packageInfo.packageName = packageName;
packageInfo.applicationInfo = new ApplicationInfo();
packageInfo.applicationInfo.uid = uid;
- mShadowPackageManager.addPackage(packageInfo);
+ mShadowPackageManager.installPackage(packageInfo);
+ ShadowApplicationPackageManager.addInstalledPackage(packageName, packageInfo);
}
private IRestoreSession createActiveRestoreSession(
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java b/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
index 5fffb149fd96..aefc871d2639 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowAppBackupUtils.java
@@ -54,7 +54,10 @@ public class ShadowAppBackupUtils {
@Implementation
protected static boolean appIsRunningAndEligibleForBackupWithTransport(
- @Nullable TransportClient transportClient, String packageName, PackageManager pm) {
+ @Nullable TransportClient transportClient,
+ String packageName,
+ PackageManager pm,
+ int userId) {
return sAppsRunningAndEligibleForBackupWithTransport.contains(packageName);
}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
new file mode 100644
index 000000000000..dc322094add8
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowApplicationPackageManager.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.testing.shadows;
+
+import static android.content.pm.PackageManager.NameNotFoundException;
+
+import android.app.ApplicationPackageManager;
+import android.content.pm.PackageInfo;
+import android.util.ArrayMap;
+
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Extends {@link org.robolectric.shadows.ShadowApplicationPackageManager} to return the correct
+ * package in user-specific invocations.
+ */
+@Implements(value = ApplicationPackageManager.class)
+public class ShadowApplicationPackageManager
+ extends org.robolectric.shadows.ShadowApplicationPackageManager {
+ private static final Map<String, PackageInfo> sPackageInfos = new ArrayMap<>();
+ private static final List<PackageInfo> sInstalledPackages = new ArrayList<>();
+
+ /**
+ * Registers the package {@code packageName} to be returned when invoking {@link
+ * ApplicationPackageManager#getPackageInfoAsUser(String, int, int)} and {@link
+ * ApplicationPackageManager#getInstalledPackagesAsUser(int, int)}.
+ */
+ public static void addInstalledPackage(String packageName, PackageInfo packageInfo) {
+ sPackageInfos.put(packageName, packageInfo);
+ sInstalledPackages.add(packageInfo);
+ }
+
+ @Override
+ protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+ throws NameNotFoundException {
+ if (!sPackageInfos.containsKey(packageName)) {
+ throw new NameNotFoundException(packageName);
+ }
+ return sPackageInfos.get(packageName);
+ }
+
+ @Override
+ protected List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
+ return sInstalledPackages;
+ }
+
+ /** Clear package state. */
+ @Resetter
+ public static void reset() {
+ sPackageInfos.clear();
+ sInstalledPackages.clear();
+ org.robolectric.shadows.ShadowApplicationPackageManager.reset();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
index 8109b1c56207..1dfce51725f1 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppErrorDialogTest.java
@@ -26,6 +26,7 @@ import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.appop.AppOpsService;
+import com.android.server.wm.ActivityTaskManagerService;
import org.junit.Before;
import org.junit.Test;
@@ -62,13 +63,15 @@ public class AppErrorDialogTest {
return false;
}
});
+ mService.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+ mService.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
}
@Test
@UiThreadTest
public void testCreateWorks() {
AppErrorDialog.Data data = new AppErrorDialog.Data();
- data.proc = new ProcessRecord(null, mContext.getApplicationInfo(), "name", 12345);
+ data.proc = new ProcessRecord(mService, mContext.getApplicationInfo(), "name", 12345);
data.result = new AppErrorResult();
AppErrorDialog dialog = new AppErrorDialog(mContext, mService, data);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 517b5ade44b8..6d28ed19af4f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -35,6 +35,7 @@ import static org.junit.Assert.fail;
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.SuspendDialogInfo;
@@ -226,8 +227,8 @@ public class PackageManagerSettingsTests {
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
// now read and verify
settingsUnderTest.readPackageRestrictionsLPr(0);
- final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1).
- readUserState(0);
+ final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
+ .readUserState(0);
assertThat(readPus1.suspended, is(true));
assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
assertThat(readPus1.dialogInfo, equalTo(dialogInfo1));
@@ -235,16 +236,16 @@ public class PackageManagerSettingsTests {
assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
is(true));
- final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2).
- readUserState(0);
+ final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
+ .readUserState(0);
assertThat(readPus2.suspended, is(true));
assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
assertThat(readPus2.dialogInfo, is(nullValue()));
assertThat(readPus2.suspendedAppExtras, is(nullValue()));
assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
- final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
- readUserState(0);
+ final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
+ .readUserState(0);
assertThat(readPus3.suspended, is(false));
assertThat(readPus3.suspendingPackage, is(nullValue()));
assertThat(readPus3.dialogInfo, is(nullValue()));
@@ -254,11 +255,59 @@ public class PackageManagerSettingsTests {
@Test
public void testPackageRestrictionsSuspendedDefault() {
- final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
+ final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
assertThat(defaultSetting.getSuspended(0), is(false));
}
@Test
+ public void testReadWritePackageRestrictions_distractionFlags() {
+ final Context context = InstrumentationRegistry.getTargetContext();
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+ final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
+ final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
+ final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
+
+ final int distractionFlags1 = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+ ps1.setDistractionFlags(distractionFlags1, 0);
+ settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
+
+ final int distractionFlags2 = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS
+ | PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+ ps2.setDistractionFlags(distractionFlags2, 0);
+ settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
+
+ final int distractionFlags3 = PackageManager.RESTRICTION_NONE;
+ ps3.setDistractionFlags(distractionFlags3, 0);
+ settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
+
+ settingsUnderTest.writePackageRestrictionsLPr(0);
+
+ settingsUnderTest.mPackages.clear();
+ settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
+ settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
+ settingsUnderTest.mPackages.put(PACKAGE_NAME_3, createPackageSetting(PACKAGE_NAME_3));
+ // now read and verify
+ settingsUnderTest.readPackageRestrictionsLPr(0);
+ final PackageUserState readPus1 = settingsUnderTest.mPackages.get(PACKAGE_NAME_1)
+ .readUserState(0);
+ assertThat(readPus1.distractionFlags, is(distractionFlags1));
+
+ final PackageUserState readPus2 = settingsUnderTest.mPackages.get(PACKAGE_NAME_2)
+ .readUserState(0);
+ assertThat(readPus2.distractionFlags, is(distractionFlags2));
+
+ final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3)
+ .readUserState(0);
+ assertThat(readPus3.distractionFlags, is(distractionFlags3));
+ }
+
+ @Test
+ public void testPackageRestrictionsDistractionFlagsDefault() {
+ final PackageSetting defaultSetting = createPackageSetting(PACKAGE_NAME_1);
+ assertThat(defaultSetting.getDistractionFlags(0), is(PackageManager.RESTRICTION_NONE));
+ }
+
+ @Test
public void testEnableDisable() {
// Write the package files and make sure they're parsed properly the first time
writeOldFiles();
@@ -692,6 +741,7 @@ public class PackageManagerSettingsTests {
assertThat(userState.notLaunched, is(notLaunched));
assertThat(userState.stopped, is(stopped));
assertThat(userState.suspended, is(false));
+ assertThat(userState.distractionFlags, is(0));
if (oldUserState != null) {
assertThat(userState.equals(oldUserState), is(not(userStateChanged)));
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index f0ed612400ed..8eaf35f6432f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -22,6 +22,7 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
+import android.content.pm.PackageManager;
import android.content.pm.PackageUserState;
import android.content.pm.SuspendDialogInfo;
import android.os.PersistableBundle;
@@ -227,4 +228,19 @@ public class PackageUserStateTest {
assertThat(testUserState1.equals(testUserState2), is(true));
}
+ @Test
+ public void testPackageUserState06() {
+ final PackageUserState userState1 = new PackageUserState();
+ assertThat(userState1.distractionFlags, is(PackageManager.RESTRICTION_NONE));
+ userState1.distractionFlags = PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS;
+
+ final PackageUserState copyOfUserState1 = new PackageUserState(userState1);
+ assertThat(userState1.distractionFlags, is(copyOfUserState1.distractionFlags));
+ assertThat(userState1.equals(copyOfUserState1), is(true));
+
+ final PackageUserState userState2 = new PackageUserState(userState1);
+ userState2.distractionFlags = PackageManager.RESTRICTION_HIDE_NOTIFICATIONS;
+ assertThat(userState1.equals(userState2), is(false));
+ }
+
}
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
index b315e514d6a6..efefee119e5f 100644
--- a/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/slice/SlicePermissionManagerTest.java
@@ -16,6 +16,7 @@ package com.android.server.slice;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import android.content.ContentProvider;
import android.content.ContentResolver;
@@ -26,6 +27,7 @@ import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.Log;
import android.util.Xml.Encoding;
import com.android.server.UiServiceTestCase;
@@ -46,10 +48,12 @@ import java.io.IOException;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class SlicePermissionManagerTest extends UiServiceTestCase {
+ private static final String TAG = "SlicePerManTest";
@Test
public void testGrant() {
- File sliceDir = new File(mContext.getDataDir(), "system/slices");
+ File sliceDir = new File(mContext.getCacheDir(), "testGrantSlices");
+ Log.v(TAG, "testGrant: slice permissions stored in " + sliceDir.getAbsolutePath());
SlicePermissionManager permissions = new SlicePermissionManager(mContext,
TestableLooper.get(this).getLooper(), sliceDir);
Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
@@ -59,11 +63,15 @@ public class SlicePermissionManagerTest extends UiServiceTestCase {
permissions.grantSliceAccess("my.pkg", 0, "provider.pkg", 0, uri);
assertTrue(permissions.hasPermission("my.pkg", 0, uri));
+
+ // Cleanup.
+ assertTrue(FileUtils.deleteContentsAndDir(sliceDir));
}
@Test
public void testBackup() throws XmlPullParserException, IOException {
- File sliceDir = new File(mContext.getDataDir(), "system/slices");
+ File sliceDir = new File(mContext.getCacheDir(), "testBackupSlices");
+ Log.v(TAG, "testBackup: slice permissions stored in " + sliceDir.getAbsolutePath());
Uri uri = new Builder().scheme(ContentResolver.SCHEME_CONTENT)
.authority("authority")
.path("something").build();
@@ -90,7 +98,10 @@ public class SlicePermissionManagerTest extends UiServiceTestCase {
TestableLooper.get(this).getLooper());
permissions.readRestore(parser);
- assertTrue(permissions.hasFullAccess("com.android.mypkg", 10));
+ if (!permissions.hasFullAccess("com.android.mypkg", 10)) {
+ fail("com.android.mypkg@10 did not have full access. backup file: "
+ + output.toString());
+ }
assertTrue(permissions.hasPermission("com.android.otherpkg", 0,
ContentProvider.maybeAddUserId(uri, 1)));
permissions.removePkg("com.android.lastpkg", 1);
@@ -102,8 +113,9 @@ public class SlicePermissionManagerTest extends UiServiceTestCase {
}
@Test
- public void testInvalid() throws Exception {
- File sliceDir = new File(mContext.getCacheDir(), "slices-test");
+ public void testInvalid() {
+ File sliceDir = new File(mContext.getCacheDir(), "testInvalidSlices");
+ Log.v(TAG, "testInvalid: slice permissions stored in " + sliceDir.getAbsolutePath());
if (!sliceDir.exists()) {
sliceDir.mkdir();
}
@@ -118,7 +130,8 @@ public class SlicePermissionManagerTest extends UiServiceTestCase {
@Override
public void writeTo(XmlSerializer out) throws IOException {
- throw new RuntimeException("this doesn't work");
+ throw new RuntimeException("this RuntimeException inside junk.writeTo() "
+ + "should be caught and suppressed by surrounding code");
}
};
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 904d55e6d0f3..00c75480ba80 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -418,12 +418,10 @@ public class UsbHostManager {
parser.getRawDescriptors());
// Stats collection
- if (parser.hasAudioInterface()) {
- StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(),
- newDevice.getProductId(), parser.hasAudioInterface(),
- parser.hasHIDInterface(), parser.hasStorageInterface(),
- StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
- }
+ StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(),
+ newDevice.getProductId(), parser.hasAudioInterface(),
+ parser.hasHIDInterface(), parser.hasStorageInterface(),
+ StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0);
}
}
@@ -455,14 +453,12 @@ public class UsbHostManager {
if (current != null) {
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress,
current.mDescriptors);
- if (parser.hasAudioInterface()) {
// Stats collection
- StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(),
- device.getProductId(), parser.hasAudioInterface(),
- parser.hasHIDInterface(), parser.hasStorageInterface(),
- StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
- System.currentTimeMillis() - current.mTimestamp);
- }
+ StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(),
+ device.getProductId(), parser.hasAudioInterface(),
+ parser.hasHIDInterface(), parser.hasStorageInterface(),
+ StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED,
+ System.currentTimeMillis() - current.mTimestamp);
}
} else {
Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone");
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 2fc3a0dd874e..7dc83c3db868 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -46,7 +46,7 @@ cc_defaults {
},
}
-cc_library_host_static {
+cc_library_static {
name: "libviewcompiler",
defaults: ["viewcompiler_defaults"],
srcs: [
@@ -58,9 +58,10 @@ cc_library_host_static {
"util.cc",
"layout_validation.cc",
],
+ host_supported: true,
}
-cc_binary_host {
+cc_binary {
name: "viewcompiler",
defaults: ["viewcompiler_defaults"],
srcs: [
@@ -70,6 +71,7 @@ cc_binary_host {
"libgflags",
"libviewcompiler",
],
+ host_supported: true
}
cc_test_host {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 84256037b379..05d5a13092f1 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -505,6 +505,14 @@ public abstract class Connection extends Conferenceable {
"android.telecom.extra.ORIGINAL_CONNECTION_ID";
/**
+ * Boolean connection extra key set on the extras passed to
+ * {@link Connection#sendConnectionEvent} which indicates that audio is present
+ * on the RTT call when the extra value is true.
+ */
+ public static final String EXTRA_IS_RTT_AUDIO_PRESENT =
+ "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
+
+ /**
* Connection event used to inform Telecom that it should play the on hold tone. This is used
* to play a tone when the peer puts the current call on hold. Sent to Telecom via
* {@link #sendConnectionEvent(String, Bundle)}.
@@ -619,6 +627,13 @@ public abstract class Connection extends Conferenceable {
*/
public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
+ /**
+ * Connection event used to inform an {@link InCallService} that the RTT audio indication
+ * has changed.
+ */
+ public static final String EVENT_RTT_AUDIO_INDICATION_CHANGED =
+ "android.telecom.event.RTT_AUDIO_INDICATION_CHANGED";
+
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index a16d7eb2ec03..c81670139eae 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -296,7 +296,7 @@ public class PhoneStateListener {
/**
* Listen for changes to preferred data subId.
- * See {@link SubscriptionManager#setPreferredData(int)}
+ * See {@link SubscriptionManager#setPreferredDataSubId(int)}
* for more details.
*
* @see #onPreferredDataSubIdChanged
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 34f7abd79a70..9fa4c3ce899f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2453,10 +2453,39 @@ public class SubscriptionManager {
*
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setPreferredData(int subId) {
- if (VDBG) logd("[setPreferredData]+ subId:" + subId);
- setSubscriptionPropertyHelper(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
- "setPreferredData", (iSub)-> iSub.setPreferredData(subId));
+ public void setPreferredDataSubscriptionId(int subId) {
+ if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
+ setSubscriptionPropertyHelper(DEFAULT_SUBSCRIPTION_ID, "setPreferredDataSubscriptionId",
+ (iSub)-> iSub.setPreferredDataSubscriptionId(subId));
+ }
+
+ /**
+ * Get which subscription is preferred for cellular data.
+ * It's also usually the subscription we set up internet connection on.
+ *
+ * PreferredData overwrites user setting of default data subscription. And it's used
+ * by AlternativeNetworkService or carrier apps to switch primary and CBRS
+ * subscription dynamically in multi-SIM devices.
+ *
+ * @return preferred subscription id for cellular data. {@link DEFAULT_SUBSCRIPTION_ID} if
+ * there's no prefered subscription.
+ *
+ * @hide
+ *
+ */
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public int getPreferredDataSubscriptionId() {
+ int preferredSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ preferredSubId = iSub.getPreferredDataSubscriptionId();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return preferredSubId;
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7f7d5e7faae5..babeb7b1b61c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -9910,10 +9910,11 @@ public class TelephonyManager {
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService != null) {
- return iOpportunisticNetworkService.setPreferredData(subId, pkgForDebug);
+ return iOpportunisticNetworkService
+ .setPreferredDataSubscriptionId(subId, pkgForDebug);
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "setPreferredData RemoteException", ex);
+ Rlog.e(TAG, "setPreferredDataSubscriptionId RemoteException", ex);
}
return false;
}
@@ -9934,10 +9935,10 @@ public class TelephonyManager {
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService != null) {
- subId = iOpportunisticNetworkService.getPreferredData(pkgForDebug);
+ subId = iOpportunisticNetworkService.getPreferredDataSubscriptionId(pkgForDebug);
}
} catch (RemoteException ex) {
- Rlog.e(TAG, "getPreferredData RemoteException", ex);
+ Rlog.e(TAG, "getPreferredDataSubscriptionId RemoteException", ex);
}
return subId;
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cc9befedcdf7..42a788d0cc8e 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
import com.android.internal.telephony.euicc.IEuiccController;
@@ -40,7 +41,11 @@ import java.lang.annotation.RetentionPolicy;
* EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs.
*
* <p>You do not instantiate this class directly; instead, you retrieve an instance through
- * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}.
+ * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be
+ * created using the default eUICC.
+ *
+ * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this
+ * you can call {@link #createForCardId}.
*
* <p>See {@link #isEnabled} before attempting to use these APIs.
*/
@@ -318,10 +323,29 @@ public class EuiccManager {
public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5;
private final Context mContext;
+ private final int mCardId;
/** @hide */
public EuiccManager(Context context) {
mContext = context;
+ TelephonyManager tm = (TelephonyManager)
+ context.getSystemService(Context.TELEPHONY_SERVICE);
+ mCardId = tm.getCardIdForDefaultEuicc();
+ }
+
+ /** @hide */
+ private EuiccManager(Context context, int cardId) {
+ mContext = context;
+ mCardId = cardId;
+ }
+
+ /**
+ * Create a new EuiccManager object pinned to the given card ID.
+ *
+ * @return an EuiccManager that uses the given card ID for all calls.
+ */
+ public EuiccManager createForCardId(int cardId) {
+ return new EuiccManager(mContext, cardId);
}
/**
@@ -344,7 +368,8 @@ public class EuiccManager {
* Returns the EID identifying the eUICC hardware.
*
* <p>Requires that the calling app has carrier privileges on the active subscription on the
- * eUICC.
+ * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have
+ * access to the EID of another eUICC.
*
* @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready.
*/
@@ -354,7 +379,7 @@ public class EuiccManager {
return null;
}
try {
- return getIEuiccController().getEid();
+ return getIEuiccController().getEid(mCardId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -377,7 +402,7 @@ public class EuiccManager {
return EUICC_OTA_STATUS_UNAVAILABLE;
}
try {
- return getIEuiccController().getOtaStatus();
+ return getIEuiccController().getOtaStatus(mCardId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -387,10 +412,10 @@ public class EuiccManager {
* Attempt to download the given {@link DownloadableSubscription}.
*
* <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
- * or the calling app must be authorized to manage both the currently-active subscription and
- * the subscription to be downloaded according to the subscription metadata. Without the former,
- * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
- * intent to prompt the user to accept the download.
+ * or the calling app must be authorized to manage both the currently-active subscription on the
+ * current eUICC and the subscription to be downloaded according to the subscription metadata.
+ * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be
+ * returned in the callback intent to prompt the user to accept the download.
*
* @param subscription the subscription to download.
* @param switchAfterDownload if true, the profile will be activated upon successful download.
@@ -404,7 +429,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().downloadSubscription(subscription, switchAfterDownload,
+ getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload,
mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -471,7 +496,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().continueOperation(resolutionIntent, resolutionExtras);
+ getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -503,8 +528,8 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().getDownloadableSubscriptionMetadata(
- subscription, mContext.getOpPackageName(), callbackIntent);
+ getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription,
+ mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -533,7 +558,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().getDefaultDownloadableSubscriptionList(
+ getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId,
mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -552,7 +577,7 @@ public class EuiccManager {
return null;
}
try {
- return getIEuiccController().getEuiccInfo();
+ return getIEuiccController().getEuiccInfo(mCardId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -578,7 +603,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().deleteSubscription(
+ getIEuiccController().deleteSubscription(mCardId,
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -606,7 +631,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().switchToSubscription(
+ getIEuiccController().switchToSubscription(mCardId,
subscriptionId, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -632,7 +657,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().updateSubscriptionNickname(
+ getIEuiccController().updateSubscriptionNickname(mCardId,
subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -656,7 +681,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().eraseSubscriptions(callbackIntent);
+ getIEuiccController().eraseSubscriptions(mCardId, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -686,7 +711,7 @@ public class EuiccManager {
return;
}
try {
- getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent);
+ getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index df903cc270a2..397d5d9b4eb5 100644
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -443,6 +443,13 @@ public class ImsCallSession {
public void callSessionRttMessageReceived(String rttMessage) {
// no-op
}
+
+ /**
+ * While in call, there has been a change in RTT audio indicator.
+ */
+ public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) {
+ // no-op
+ }
}
private final IImsCallSession miSession;
@@ -1397,6 +1404,16 @@ public class ImsCallSession {
mListener.callSessionRttMessageReceived(rttMessage);
}
}
+
+ /**
+ * While in call, there has been a change in RTT audio indicator.
+ */
+ @Override
+ public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionRttAudioIndicatorChanged(profile);
+ }
+ }
}
/**
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index a7f124a5b791..a4696a3f93aa 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -599,5 +599,18 @@ public class ImsCallSessionListener {
throw new RuntimeException(e);
}
}
+
+ /**
+ * While in call, there has been a change in RTT audio indicator.
+ *
+ * @param profile updated ImsStreamMediaProfile
+ */
+ public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile) {
+ try {
+ mListener.callSessionRttAudioIndicatorChanged(profile);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
index 52d72b5847b5..837ef54a2f24 100644
--- a/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/android/telephony/ims/ImsStreamMediaProfile.java
@@ -97,6 +97,9 @@ public final class ImsStreamMediaProfile implements Parcelable {
// Rtt related information
/** @hide */
public int mRttMode;
+ // RTT Audio Speech Indicator
+ /** @hide */
+ public boolean mHasRttAudioSpeech = false;
/** @hide */
public ImsStreamMediaProfile(Parcel in) {
@@ -197,7 +200,8 @@ public final class ImsStreamMediaProfile implements Parcelable {
", audioDirection=" + mAudioDirection +
", videoQuality=" + mVideoQuality +
", videoDirection=" + mVideoDirection +
- ", rttMode=" + mRttMode + " }";
+ ", rttMode=" + mRttMode +
+ ", hasRttAudioSpeech=" + mHasRttAudioSpeech + " }";
}
@Override
@@ -212,6 +216,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
out.writeInt(mVideoQuality);
out.writeInt(mVideoDirection);
out.writeInt(mRttMode);
+ out.writeBoolean(mHasRttAudioSpeech);
}
private void readFromParcel(Parcel in) {
@@ -220,6 +225,7 @@ public final class ImsStreamMediaProfile implements Parcelable {
mVideoQuality = in.readInt();
mVideoDirection = in.readInt();
mRttMode = in.readInt();
+ mHasRttAudioSpeech = in.readBoolean();
}
public static final Creator<ImsStreamMediaProfile> CREATOR =
@@ -250,6 +256,10 @@ public final class ImsStreamMediaProfile implements Parcelable {
mRttMode = rttMode;
}
+ public void setRttAudioSpeech(boolean audioOn) {
+ mHasRttAudioSpeech = audioOn;
+ }
+
public int getAudioQuality() {
return mAudioQuality;
}
@@ -269,4 +279,8 @@ public final class ImsStreamMediaProfile implements Parcelable {
public int getRttMode() {
return mRttMode;
}
+
+ public boolean getRttAudioSpeech() {
+ return mHasRttAudioSpeech;
+ }
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
index f25b4b148605..d0b31e16a4f0 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsCallSessionListener.aidl
@@ -138,4 +138,10 @@ oneway interface IImsCallSessionListener {
* @param rttMessage Received RTT message
*/
void callSessionRttMessageReceived(in String rttMessage);
+
+ /*
+ * While in call, there has been a change in RTT audio indicator.
+ * @param profile updated ImsStreamMediaProfile
+ */
+ void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
}
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
index 23de2fd3c32c..bc58e46806c2 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsCallSessionImplBase.java
@@ -591,5 +591,11 @@ public class ImsCallSessionImplBase extends IImsCallSession.Stub {
public void callSessionRttMessageReceived(String rttMessage) throws RemoteException {
mNewListener.callSessionRttMessageReceived(rttMessage);
}
+
+ @Override
+ public void callSessionRttAudioIndicatorChanged(ImsStreamMediaProfile profile)
+ throws RemoteException {
+ mNewListener.callSessionRttAudioIndicatorChanged(profile);
+ }
}
}
diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
index a8e8b7dd03aa..bbb27af1ba36 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl
@@ -152,4 +152,10 @@ oneway interface IImsCallSessionListener {
* @param rttMessage Received RTT message
*/
void callSessionRttMessageReceived(in String rttMessage);
+
+ /*
+ * While in call, there has been a change in RTT audio indicator.
+ * @param profile updated ImsStreamMediaProfile
+ */
+ void callSessionRttAudioIndicatorChanged(in ImsStreamMediaProfile profile);
}
diff --git a/telephony/java/com/android/internal/telephony/IOns.aidl b/telephony/java/com/android/internal/telephony/IOns.aidl
index d6779f1fb334..0e3d12b7f838 100755
--- a/telephony/java/com/android/internal/telephony/IOns.aidl
+++ b/telephony/java/com/android/internal/telephony/IOns.aidl
@@ -66,7 +66,7 @@ interface IOns {
* @return true if request is accepted, else false.
*
*/
- boolean setPreferredData(int subId, String callingPackage);
+ boolean setPreferredDataSubscriptionId(int subId, String callingPackage);
/**
* Get preferred opportunistic data subscription Id
@@ -78,7 +78,7 @@ interface IOns {
* subscription id
*
*/
- int getPreferredData(String callingPackage);
+ int getPreferredDataSubscriptionId(String callingPackage);
/**
* Update availability of a list of networks in the current location.
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index d169b7d04f5c..577ddbda50fa 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -200,7 +200,15 @@ interface ISub {
* @hide
*
*/
- int setPreferredData(int subId);
+ int setPreferredDataSubscriptionId(int subId);
+
+ /**
+ * Get which subscription is preferred for cellular data.
+ *
+ * @hide
+ *
+ */
+ int getPreferredDataSubscriptionId();
/**
* Get User downloaded Profiles.
diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
index dd40d560250d..14a36c8c840d 100644
--- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
+++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl
@@ -24,22 +24,25 @@ import android.telephony.euicc.EuiccInfo;
/** @hide */
interface IEuiccController {
- oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras);
- oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription,
+ oneway void continueOperation(int cardId, in Intent resolutionIntent,
+ in Bundle resolutionExtras);
+ oneway void getDownloadableSubscriptionMetadata(int cardId,
+ in DownloadableSubscription subscription,
String callingPackage, in PendingIntent callbackIntent);
- oneway void getDefaultDownloadableSubscriptionList(
+ oneway void getDefaultDownloadableSubscriptionList(int cardId,
String callingPackage, in PendingIntent callbackIntent);
- String getEid();
- int getOtaStatus();
- oneway void downloadSubscription(in DownloadableSubscription subscription,
- boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent);
- EuiccInfo getEuiccInfo();
- oneway void deleteSubscription(int subscriptionId, String callingPackage,
+ String getEid(int cardId);
+ int getOtaStatus(int cardId);
+ oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription,
+ boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle,
in PendingIntent callbackIntent);
- oneway void switchToSubscription(int subscriptionId, String callingPackage,
+ EuiccInfo getEuiccInfo(int cardId);
+ oneway void deleteSubscription(int cardId, int subscriptionId, String callingPackage,
in PendingIntent callbackIntent);
- oneway void updateSubscriptionNickname(int subscriptionId, String nickname,
+ oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage,
+ in PendingIntent callbackIntent);
+ oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname,
String callingPackage, in PendingIntent callbackIntent);
- oneway void eraseSubscriptions(in PendingIntent callbackIntent);
- oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent);
-} \ No newline at end of file
+ oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent);
+ oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent);
+}
diff --git a/tests/PackageWatchdog/Android.mk b/tests/PackageWatchdog/Android.mk
index b53f27d28740..1c1c2a426d15 100644
--- a/tests/PackageWatchdog/Android.mk
+++ b/tests/PackageWatchdog/Android.mk
@@ -23,7 +23,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
junit \
frameworks-base-testutils \
android-support-test \
- services
+ services.core
LOCAL_JAVA_LIBRARIES := \
android.test.runner
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index f82b380f5d43..932fee0c1956 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -18,6 +18,7 @@ package android.net;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -33,6 +34,9 @@ import android.support.test.runner.AndroidJUnit4;
import android.system.OsConstants;
import android.util.ArraySet;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -41,9 +45,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class LinkPropertiesTest {
@@ -504,6 +505,40 @@ public class LinkPropertiesTest {
}
@Test
+ public void testNat64Prefix() throws Exception {
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(LINKADDRV4);
+ lp.addLinkAddress(LINKADDRV6);
+
+ assertNull(lp.getNat64Prefix());
+
+ IpPrefix p = new IpPrefix("64:ff9b::/96");
+ lp.setNat64Prefix(p);
+ assertEquals(p, lp.getNat64Prefix());
+
+ p = new IpPrefix("2001:db8:a:b:1:2:3::/96");
+ lp.setNat64Prefix(p);
+ assertEquals(p, lp.getNat64Prefix());
+
+ p = new IpPrefix("2001:db8:a:b:1:2::/80");
+ try {
+ lp.setNat64Prefix(p);
+ } catch (IllegalArgumentException expected) {
+ }
+
+ p = new IpPrefix("64:ff9b::/64");
+ try {
+ lp.setNat64Prefix(p);
+ } catch (IllegalArgumentException expected) {
+ }
+
+ assertEquals(new IpPrefix("2001:db8:a:b:1:2:3::/96"), lp.getNat64Prefix());
+
+ lp.setNat64Prefix(null);
+ assertNull(lp.getNat64Prefix());
+ }
+
+ @Test
public void testIsProvisioned() {
LinkProperties lp4 = new LinkProperties();
assertFalse("v4only:empty", lp4.isProvisioned());
@@ -815,7 +850,7 @@ public class LinkPropertiesTest {
}
@Test
- public void testLinkPropertiesParcelable() {
+ public void testLinkPropertiesParcelable() throws Exception {
LinkProperties source = new LinkProperties();
source.setInterfaceName(NAME);
// set 2 link addresses
@@ -833,6 +868,8 @@ public class LinkPropertiesTest {
source.setMtu(MTU);
+ source.setNat64Prefix(new IpPrefix("2001:db8:1:2:64:64::/96"));
+
Parcel p = Parcel.obtain();
source.writeToParcel(p, /* flags */ 0);
p.setDataPosition(0);
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 0580df60f32a..7783e108f674 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -115,6 +115,7 @@ cc_library_host_static {
"optimize/MultiApkGenerator.cpp",
"optimize/ResourceDeduper.cpp",
"optimize/ResourceFilter.cpp",
+ "optimize/ResourcePathShortener.cpp",
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
"split/TableSplitter.cpp",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index b353ff00a23f..45719ef474cd 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -223,8 +223,17 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
io::IFile* file = iterator->Next();
std::string path = file->GetSource().path;
+ std::string output_path = path;
+ bool is_resource = path.find("res/") == 0;
+ if (is_resource) {
+ auto it = options.shortened_path_map.find(path);
+ if (it != options.shortened_path_map.end()) {
+ output_path = it->second;
+ }
+ }
+
// Skip resources that are not referenced if requested.
- if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) {
+ if (is_resource && referenced_resources.find(output_path) == referenced_resources.end()) {
if (context->IsVerbose()) {
context->GetDiagnostics()->Note(DiagMessage()
<< "Removing resource '" << path << "' from APK.");
@@ -283,7 +292,8 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table
return false;
}
} else {
- if (!io::CopyFileToArchivePreserveCompression(context, file, path, writer)) {
+ if (!io::CopyFileToArchivePreserveCompression(
+ context, file, output_path, writer)) {
return false;
}
}
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 328b0beda372..2e6af18c1948 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -41,6 +41,7 @@
#include "optimize/MultiApkGenerator.h"
#include "optimize/ResourceDeduper.h"
#include "optimize/ResourceFilter.h"
+#include "optimize/ResourcePathShortener.h"
#include "optimize/VersionCollapser.h"
#include "split/TableSplitter.h"
#include "util/Files.h"
@@ -52,6 +53,7 @@ using ::android::ConfigDescription;
using ::android::ResTable_config;
using ::android::StringPiece;
using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFile;
using ::android::base::StringAppendF;
using ::android::base::StringPrintf;
@@ -143,6 +145,21 @@ class Optimizer {
return 1;
}
+ if (options_.shorten_resource_paths) {
+ ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map);
+ if (!shortener.Consume(context_, apk->GetResourceTable())) {
+ context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths");
+ return 1;
+ }
+ if (options_.shortened_paths_map_path
+ && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
+ options_.shortened_paths_map_path.value())) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed to write shortened resource paths to file");
+ return 1;
+ }
+ }
+
// Adjust the SplitConstraints so that their SDK version is stripped if it is less than or
// equal to the minSdk.
options_.split_constraints =
@@ -264,6 +281,15 @@ class Optimizer {
ArchiveEntry::kAlign, writer);
}
+ bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
+ const std::string &file_path) {
+ std::stringstream ss;
+ for (auto it = path_map.cbegin(); it != path_map.cend(); ++it) {
+ ss << it->first << " -> " << it->second << "\n";
+ }
+ return WriteStringToFile(ss.str(), file_path);
+ }
+
OptimizeOptions options_;
OptimizeContext* context_;
};
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index d07305bc3e04..7f4a3ed85364 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -55,6 +55,12 @@ struct OptimizeOptions {
// Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
// are kept and will be written as output.
std::unordered_set<std::string> kept_artifacts;
+
+ // Whether or not to shorten resource paths in the APK.
+ bool shorten_resource_paths;
+
+ // Path to the output map of original resource paths to shortened paths.
+ Maybe<std::string> shortened_paths_map_path;
};
class OptimizeCommand : public Command {
@@ -101,6 +107,12 @@ class OptimizeCommand : public Command {
AddOptionalSwitch("--enable-resource-obfuscation",
"Enables obfuscation of key string pool to single value",
&options_.table_flattener_options.collapse_key_stringpool);
+ AddOptionalSwitch("--enable-resource-path-shortening",
+ "Enables shortening of the path of the resources inside the APK.",
+ &options_.shorten_resource_paths);
+ AddOptionalFlag("--resource-path-shortening-map",
+ "Path to output the map of old resource paths to shortened paths.",
+ &options_.shortened_paths_map_path);
AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
}
@@ -109,6 +121,9 @@ class OptimizeCommand : public Command {
private:
OptimizeOptions options_;
+ bool WriteObfuscatedPathsMap(const std::map<std::string, std::string> &path_map,
+ const std::string &file_path);
+
Maybe<std::string> config_path_;
Maybe<std::string> whitelist_path_;
Maybe<std::string> resources_config_path_;
@@ -122,4 +137,4 @@ class OptimizeCommand : public Command {
}// namespace aapt
-#endif //AAPT2_OPTIMIZE_H \ No newline at end of file
+#endif //AAPT2_OPTIMIZE_H
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index c496ff0e159b..7d4c6f348403 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -42,6 +42,19 @@ namespace aapt {
namespace {
+static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) {
+ size_t utf16_len = strnlen16(src, len);
+ if (utf16_len == 0) {
+ return {};
+ }
+ std::u16string dst;
+ dst.resize(utf16_len);
+ for (size_t i = 0; i < utf16_len; i++) {
+ dst[i] = util::DeviceToHost16(src[i]);
+ }
+ return dst;
+}
+
// Visitor that converts a reference's resource ID to a resource name, given a mapping from
// resource ID to resource name.
class ReferenceIdToNameVisitor : public DescendingValueVisitor {
@@ -176,12 +189,8 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) {
}
// Extract the package name.
- size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name));
- std::u16string package_name;
- package_name.resize(len);
- for (size_t i = 0; i < len; i++) {
- package_name[i] = util::DeviceToHost16(package_header->name[i]);
- }
+ std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name,
+ arraysize(package_header->name));
ResourceTablePackage* package =
table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
@@ -435,6 +444,11 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) {
}
auto overlayable = std::make_shared<Overlayable>();
+ overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name,
+ arraysize(header->name)));
+ overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor,
+ arraysize(header->name)));
+ overlayable->source = source_.WithLine(0);
ResChunkPullParser parser(GetChunkData(chunk),
GetChunkDataLen(chunk));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 931d57b1c08a..c4ecbafc008b 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -217,9 +217,10 @@ class MapFlattenVisitor : public ValueVisitor {
size_t entry_count_ = 0;
};
-struct PolicyChunk {
- uint32_t policy_flags;
- std::set<ResourceId> ids;
+struct OverlayableChunk {
+ std::string actor;
+ Source source;
+ std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids;
};
class PackageFlattener {
@@ -421,8 +422,9 @@ class PackageFlattener {
return sorted_entries;
}
- void FlattenOverlayable(BigBuffer* buffer) {
- std::vector<PolicyChunk> policies;
+ bool FlattenOverlayable(BigBuffer* buffer) {
+ std::set<ResourceId> seen_ids;
+ std::map<std::string, OverlayableChunk> overlayable_chunks;
CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>";
for (auto& type : package_->types) {
@@ -433,79 +435,119 @@ class PackageFlattener {
continue;
}
- OverlayableItem& overlayable = entry->overlayable_item.value();
- uint32_t policy_flags = OverlayableItem::Policy::kNone;
- if (overlayable.policies & OverlayableItem::Policy::kPublic) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
- }
- if (overlayable.policies & OverlayableItem::Policy::kSystem) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
- }
- if (overlayable.policies & OverlayableItem::Policy::kVendor) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
- }
- if (overlayable.policies & OverlayableItem::Policy::kProduct) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
- }
- if (overlayable.policies & OverlayableItem::Policy::kProductServices) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
+ OverlayableItem& item = entry->overlayable_item.value();
+
+ // Resource ids should only appear once in the resource table
+ ResourceId id = android::make_resid(package_->id.value(), type->id.value(),
+ entry->id.value());
+ CHECK(seen_ids.find(id) == seen_ids.end())
+ << "multiple overlayable definitions found for resource "
+ << ResourceName(package_->name, type->type, entry->name).to_string();
+ seen_ids.insert(id);
+
+ // Find the overlayable chunk with the specified name
+ OverlayableChunk* overlayable_chunk = nullptr;
+ auto iter = overlayable_chunks.find(item.overlayable->name);
+ if (iter == overlayable_chunks.end()) {
+ OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source};
+ overlayable_chunk =
+ &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second;
+ } else {
+ OverlayableChunk& chunk = iter->second;
+ if (!(chunk.source == item.overlayable->source)) {
+ // The name of an overlayable set of resources must be unique
+ context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source)
+ << "duplicate overlayable name"
+ << item.overlayable->name << "'");
+ context_->GetDiagnostics()->Error(DiagMessage(chunk.source)
+ << "previous declaration here");
+ return false;
+ }
+
+ CHECK(chunk.actor == item.overlayable->actor);
+ overlayable_chunk = &chunk;
}
- if (overlayable.policies == OverlayableItem::Policy::kNone) {
+ uint32_t policy_flags = 0;
+ if (item.policies == OverlayableItem::Policy::kNone) {
// Encode overlayable entries defined without a policy as publicly overlayable
policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
- }
-
- // Find the overlayable policy chunk with the same policies as the entry
- PolicyChunk* policy_chunk = nullptr;
- for (PolicyChunk& policy : policies) {
- if (policy.policy_flags == policy_flags) {
- policy_chunk = &policy;
- break;
+ } else {
+ if (item.policies & OverlayableItem::Policy::kPublic) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC;
+ }
+ if (item.policies & OverlayableItem::Policy::kSystem) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kVendor) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kProduct) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
+ }
+ if (item.policies & OverlayableItem::Policy::kProductServices) {
+ policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
}
}
- // Create a new policy chunk if an existing one with the same policy cannot be found
- if (policy_chunk == nullptr) {
- PolicyChunk p;
- p.policy_flags = policy_flags;
- policies.push_back(p);
- policy_chunk = &policies.back();
+ auto policy = overlayable_chunk->policy_ids.find(policy_flags);
+ if (policy != overlayable_chunk->policy_ids.end()) {
+ policy->second.insert(id);
+ } else {
+ overlayable_chunk->policy_ids.insert(
+ std::make_pair(policy_flags, std::set<ResourceId>{id}));
}
-
- policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(),
- entry->id.value()));
}
}
- if (policies.empty()) {
- // Only write the overlayable chunk if the APK has overlayable entries
- return;
- }
-
- ChunkWriter writer(buffer);
- writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
-
- // Write each policy block for the overlayable
- for (PolicyChunk& policy : policies) {
- ChunkWriter policy_writer(buffer);
- ResTable_overlayable_policy_header* policy_type =
- policy_writer.StartChunk<ResTable_overlayable_policy_header>(
- RES_TABLE_OVERLAYABLE_POLICY_TYPE);
- policy_type->policy_flags = util::HostToDevice32(policy.policy_flags);
- policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size()));
-
- // Write the ids after the policy header
- ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size());
- for (const ResourceId& id : policy.ids) {
- id_block->ident = util::HostToDevice32(id.id);
- id_block++;
+ for (auto& overlayable_pair : overlayable_chunks) {
+ std::string name = overlayable_pair.first;
+ OverlayableChunk& overlayable = overlayable_pair.second;
+
+ // Write the header of the overlayable chunk
+ ChunkWriter overlayable_writer(buffer);
+ auto* overlayable_type =
+ overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE);
+ if (name.size() >= arraysize(overlayable_type->name)) {
+ diag_->Error(DiagMessage() << "overlayable name '" << name
+ << "' exceeds maximum length ("
+ << arraysize(overlayable_type->name)
+ << " utf16 characters)");
+ return false;
}
-
- policy_writer.Finish();
+ strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name),
+ util::Utf8ToUtf16(name));
+
+ if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) {
+ diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor
+ << "' exceeds maximum length ("
+ << arraysize(overlayable_type->actor)
+ << " utf16 characters)");
+ return false;
+ }
+ strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor),
+ util::Utf8ToUtf16(overlayable.actor));
+
+ // Write each policy block for the overlayable
+ for (auto& policy_ids : overlayable.policy_ids) {
+ ChunkWriter policy_writer(buffer);
+ auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>(
+ RES_TABLE_OVERLAYABLE_POLICY_TYPE);
+ policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first));
+ policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(
+ policy_ids.second.size()));
+ // Write the ids after the policy header
+ auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size());
+ for (const ResourceId& id : policy_ids.second) {
+ id_block->ident = util::HostToDevice32(id.id);
+ id_block++;
+ }
+ policy_writer.Finish();
+ }
+ overlayable_writer.Finish();
}
- writer.Finish();
+ return true;
}
bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries,
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 635cb21f514c..71330e3fb74f 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -46,6 +46,9 @@ struct TableFlattenerOptions {
// When true, sort the entries in the values string pool by priority and configuration.
bool sort_stringpool_entries = true;
+
+ // Map from original resource paths to shortened resource paths.
+ std::map<std::string, std::string> shortened_path_map;
};
class TableFlattener : public IResourceTableConsumer {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index a5fb6fd6d7aa..18fecf60c977 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -657,36 +657,36 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) {
TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme");
std::string name_zero = "com.app.test:integer/overlayable_zero_item";
- OverlayableItem overlayable_zero_item(overlayable);
- overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct;
- overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem;
- overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices;
+ OverlayableItem overlayable_item_zero(overlayable);
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
std::string name_one = "com.app.test:integer/overlayable_one_item";
- OverlayableItem overlayable_one_item(overlayable);
- overlayable_one_item.policies |= OverlayableItem::Policy::kPublic;
- overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices;
+ OverlayableItem overlayable_item_one(overlayable);
+ overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+ overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
std::string name_two = "com.app.test:integer/overlayable_two_item";
- OverlayableItem overlayable_two_item(overlayable);
- overlayable_two_item.policies |= OverlayableItem::Policy::kProduct;
- overlayable_two_item.policies |= OverlayableItem::Policy::kSystem;
- overlayable_two_item.policies |= OverlayableItem::Policy::kVendor;
+ OverlayableItem overlayable_item_two(overlayable);
+ overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
std::string name_three = "com.app.test:integer/overlayable_three_item";
- OverlayableItem overlayable_three_item(overlayable);
+ OverlayableItem overlayable_item_three(overlayable);
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.SetPackageId("com.app.test", 0x7f)
.AddSimple(name_zero, ResourceId(0x7f020000))
- .SetOverlayable(name_zero, overlayable_zero_item)
+ .SetOverlayable(name_zero, overlayable_item_zero)
.AddSimple(name_one, ResourceId(0x7f020001))
- .SetOverlayable(name_one, overlayable_one_item)
+ .SetOverlayable(name_one, overlayable_item_one)
.AddSimple(name_two, ResourceId(0x7f020002))
- .SetOverlayable(name_two, overlayable_two_item)
+ .SetOverlayable(name_two, overlayable_item_two)
.AddSimple(name_three, ResourceId(0x7f020003))
- .SetOverlayable(name_three, overlayable_three_item)
+ .SetOverlayable(name_three, overlayable_item_three)
.Build();
ResourceTable output_table;
@@ -724,6 +724,84 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) {
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+ EXPECT_EQ(overlayable_item.overlayable->name, "TestName");
+ EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme");
+ EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
+}
+
+TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
+ auto group = std::make_shared<Overlayable>("TestName", "overlay://theme");
+ std::string name_zero = "com.app.test:integer/overlayable_zero";
+ OverlayableItem overlayable_item_zero(group);
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
+
+ auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
+ std::string name_one = "com.app.test:integer/overlayable_one";
+ OverlayableItem overlayable_item_one(group_one);
+ overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
+ overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
+
+ std::string name_two = "com.app.test:integer/overlayable_two";
+ OverlayableItem overlayable_item_two(group);
+ overlayable_item_two.policies |= OverlayableItem::Policy::kProduct;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kSystem;
+ overlayable_item_two.policies |= OverlayableItem::Policy::kVendor;
+
+ std::string name_three = "com.app.test:integer/overlayable_three";
+ OverlayableItem overlayable_item_three(group_one);
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId("com.app.test", 0x7f)
+ .AddSimple(name_zero, ResourceId(0x7f020000))
+ .SetOverlayable(name_zero, overlayable_item_zero)
+ .AddSimple(name_one, ResourceId(0x7f020001))
+ .SetOverlayable(name_one, overlayable_item_one)
+ .AddSimple(name_two, ResourceId(0x7f020002))
+ .SetOverlayable(name_two, overlayable_item_two)
+ .AddSimple(name_three, ResourceId(0x7f020003))
+ .SetOverlayable(name_three, overlayable_item_three)
+ .Build();
+ ResourceTable output_table;
+ ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table));
+ auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+ | OverlayableItem::Policy::kProduct
+ | OverlayableItem::Policy::kProductServices);
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic
+ | OverlayableItem::Policy::kProductServices);
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
+ | OverlayableItem::Policy::kProduct
+ | OverlayableItem::Policy::kVendor);
+ search_result = output_table.FindResource(test::ParseNameOrDie(name_three));
+ ASSERT_TRUE(search_result);
+ ASSERT_THAT(search_result.value().entry, NotNull());
+ ASSERT_TRUE(search_result.value().entry->overlayable_item);
+ result_overlayable = search_result.value().entry->overlayable_item.value();
+ EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
+ EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
}
} // namespace aapt
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
new file mode 100644
index 000000000000..c5df3dd00db9
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 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 "optimize/ResourcePathShortener.h"
+
+#include <math.h>
+#include <unordered_set>
+
+#include "androidfw/StringPiece.h"
+
+#include "ResourceTable.h"
+#include "ValueVisitor.h"
+
+
+static const std::string base64_chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-_";
+
+namespace aapt {
+
+ResourcePathShortener::ResourcePathShortener(
+ std::map<std::string, std::string>& path_map_out)
+ : path_map_(path_map_out) {
+}
+
+std::string ShortenFileName(const android::StringPiece& file_path, int output_length) {
+ std::size_t hash_num = std::hash<android::StringPiece>{}(file_path);
+ std::string result = "";
+ // Convert to (modified) base64 so that it is a proper file path.
+ for (int i = 0; i < output_length; i++) {
+ uint8_t sextet = hash_num & 0x3f;
+ hash_num >>= 6;
+ result += base64_chars[sextet];
+ }
+ return result;
+}
+
+
+// Calculate the optimal hash length such that an average of 10% of resources
+// collide in their shortened path.
+// Reference: http://matt.might.net/articles/counting-hash-collisions/
+int OptimalShortenedLength(int num_resources) {
+ int num_chars = 2;
+ double N = 64*64; // hash space when hash is 2 chars long
+ double max_collisions = num_resources * 0.1;
+ while (num_resources - N + N * pow((N - 1) / N, num_resources) > max_collisions) {
+ N *= 64;
+ num_chars++;
+ }
+ return num_chars;
+}
+
+std::string GetShortenedPath(const android::StringPiece& shortened_filename,
+ const android::StringPiece& extension, int collision_count) {
+ std::string shortened_path = "res/" + shortened_filename.to_string();
+ if (collision_count > 0) {
+ shortened_path += std::to_string(collision_count);
+ }
+ shortened_path += extension;
+ return shortened_path;
+}
+
+bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) {
+ // used to detect collisions
+ std::unordered_set<std::string> shortened_paths;
+ std::unordered_set<FileReference*> file_refs;
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto& entry : type->entries) {
+ for (auto& config_value : entry->values) {
+ FileReference* file_ref = ValueCast<FileReference>(config_value->value.get());
+ if (file_ref) {
+ file_refs.insert(file_ref);
+ }
+ }
+ }
+ }
+ }
+ int num_chars = OptimalShortenedLength(file_refs.size());
+ for (auto& file_ref : file_refs) {
+ android::StringPiece res_subdir, actual_filename, extension;
+ util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
+
+ std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
+ int collision_count = 0;
+ std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+ while (shortened_paths.find(shortened_path) != shortened_paths.end()) {
+ collision_count++;
+ shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
+ }
+ shortened_paths.insert(shortened_path);
+ path_map_.insert({*file_ref->path, shortened_path});
+ file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
+ }
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/optimize/ResourcePathShortener.h b/tools/aapt2/optimize/ResourcePathShortener.h
new file mode 100644
index 000000000000..f1074ef083bd
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2018 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 AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
+#define AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
+
+#include <map>
+
+#include "android-base/macros.h"
+
+#include "process/IResourceTableConsumer.h"
+
+namespace aapt {
+
+class ResourceTable;
+
+// Maps resources in the apk to shortened paths.
+class ResourcePathShortener : public IResourceTableConsumer {
+ public:
+ explicit ResourcePathShortener(std::map<std::string, std::string>& path_map_out);
+
+ bool Consume(IAaptContext* context, ResourceTable* table) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResourcePathShortener);
+ std::map<std::string, std::string>& path_map_;
+};
+
+} // namespace aapt
+
+#endif // AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
new file mode 100644
index 000000000000..88cadc76c336
--- /dev/null
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2018 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 "optimize/ResourcePathShortener.h"
+
+#include "ResourceTable.h"
+#include "test/Test.h"
+
+using ::aapt::test::GetValue;
+using ::testing::Not;
+using ::testing::NotNull;
+using ::testing::Eq;
+
+namespace aapt {
+
+TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml")
+ .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml")
+ .AddString("android:string/string", "res/should/still/be/the/same.png")
+ .Build();
+
+ std::map<std::string, std::string> path_map;
+ ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get()));
+
+ // Expect that the path map is populated
+ ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end())));
+ ASSERT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end())));
+
+ // The file paths were changed
+ EXPECT_THAT(path_map.at("res/drawables/xmlfile.xml"), Not(Eq("res/drawables/xmlfile.xml")));
+ EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml")));
+
+ // Different file paths should remain different
+ EXPECT_THAT(path_map["res/drawables/xmlfile.xml"],
+ Not(Eq(path_map["res/drawables/xmlfile2.xml"])));
+
+ FileReference* ref =
+ GetValue<FileReference>(table.get(), "android:drawable/xmlfile");
+ ASSERT_THAT(ref, NotNull());
+ // The map correctly points to the new location of the file
+ EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], Eq(*ref->path));
+
+ // Strings should not be affected, only file paths
+ EXPECT_THAT(
+ *GetValue<String>(table.get(), "android:string/string")->value,
+ Eq("res/should/still/be/the/same.png"));
+ EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end()));
+}
+
+} // namespace aapt
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index acf1f1e9902e..d1fe43ea0c7c 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -297,7 +297,7 @@ class V2Tokenizer(object):
class V2LineParser(object):
__slots__ = ["tokenized", "current", "len"]
- MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized".split())
+ MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized native operator sealed strictfp infix inline suspend vararg".split())
JAVA_LANG_TYPES = set("AbstractMethodError AbstractStringBuilder Appendable ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError AutoCloseable Boolean BootstrapMethodError Byte Character CharSequence Class ClassCastException ClassCircularityError ClassFormatError ClassLoader ClassNotFoundException Cloneable CloneNotSupportedException Comparable Compiler Deprecated Double Enum EnumConstantNotPresentException Error Exception ExceptionInInitializerError Float FunctionalInterface IllegalAccessError IllegalAccessException IllegalArgumentException IllegalMonitorStateException IllegalStateException IllegalThreadStateException IncompatibleClassChangeError IndexOutOfBoundsException InheritableThreadLocal InstantiationError InstantiationException Integer InternalError InterruptedException Iterable LinkageError Long Math NegativeArraySizeException NoClassDefFoundError NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException NullPointerException Number NumberFormatException Object OutOfMemoryError Override Package package-info.java Process ProcessBuilder ProcessEnvironment ProcessImpl Readable ReflectiveOperationException Runnable Runtime RuntimeException RuntimePermission SafeVarargs SecurityException SecurityManager Short StackOverflowError StackTraceElement StrictMath String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeNotPresentException UNIXProcess UnknownError UnsatisfiedLinkError UnsupportedClassVersionError UnsupportedOperationException VerifyError VirtualMachineError Void".split())
def __init__(self, raw):
@@ -355,7 +355,7 @@ class V2LineParser(object):
self.parse_eof()
def parse_into_field(self, field):
- kind = self.parse_token("field")
+ kind = self.parse_one_of("field", "property")
field.split = [kind]
annotations = self.parse_annotations()
if "@Deprecated" in annotations:
@@ -442,13 +442,19 @@ class V2LineParser(object):
return None
def parse_type(self):
+ self.parse_annotations()
type = self.parse_token()
+ if type[-1] == '.':
+ self.parse_annotations()
+ type += self.parse_token()
if type in V2LineParser.JAVA_LANG_TYPES:
type = "java.lang." + type
self.parse_matching_paren("<", ">")
while True:
t = self.lookahead()
- if t == "[]":
+ if t == "@":
+ self.parse_annotation()
+ elif t == "[]":
type += self.parse_token()
elif self.parse_kotlin_nullability() is not None:
pass # discard nullability for now
@@ -478,17 +484,23 @@ class V2LineParser(object):
self.parse_token(",")
def parse_arg(self):
+ self.parse_if("vararg") # kotlin vararg
self.parse_annotations()
type = self.parse_arg_type()
l = self.lookahead()
if l != "," and l != ")":
- self.parse_token() # kotlin argument name
+ if self.lookahead() != '=':
+ self.parse_token() # kotlin argument name
if self.parse_if('='): # kotlin default value
- (self.parse_matching_paren('(', ')') or
- self.parse_matching_paren('{', '}') or
- self.parse_token() and self.parse_matching_paren('(', ')'))
+ self.parse_expression()
return type
+ def parse_expression(self):
+ while not self.lookahead() in [')', ',', ';']:
+ (self.parse_matching_paren('(', ')') or
+ self.parse_matching_paren('{', '}') or
+ self.parse_token())
+
def parse_throws(self):
ret = []
if self.parse_if("throws"):
@@ -516,7 +528,7 @@ class V2LineParser(object):
def parse_annotation_default(self):
if self.parse_if("default"):
- self.parse_value()
+ self.parse_expression()
def parse_value(self):
if self.lookahead() == "{":
@@ -599,7 +611,7 @@ def _parse_stream_to_generator(f):
clazz.ctors.append(Method(clazz, line, raw, blame, sig_format=sig_format))
elif raw.startswith(" method"):
clazz.methods.append(Method(clazz, line, raw, blame, sig_format=sig_format))
- elif raw.startswith(" field"):
+ elif raw.startswith(" field") or raw.startswith(" property"):
clazz.fields.append(Field(clazz, line, raw, blame, sig_format=sig_format))
elif raw.startswith(" }") and clazz:
yield clazz
@@ -942,7 +954,7 @@ def verify_fields(clazz):
else:
error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable")
- if not "static" in f.split:
+ if "static" not in f.split and "property" not in f.split:
if not re.match("[a-z]([a-zA-Z]+)?", f.name):
error(clazz, f, "S1", "Non-static fields must be named using myField style")
@@ -1650,7 +1662,7 @@ def verify_method_name_not_kotlin_operator(clazz):
binary.add(op)
for m in clazz.methods:
- if 'static' in m.split:
+ if 'static' in m.split or 'operator' in m.split:
continue
# https://kotlinlang.org/docs/reference/operator-overloading.html#unary-prefix-operators
diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py
index 081e98defa17..fde61a902341 100644
--- a/tools/apilint/apilint_test.py
+++ b/tools/apilint/apilint_test.py
@@ -225,11 +225,12 @@ class V2ParserTests(unittest.TestCase):
self.assertEquals('pkg.SuppressLint', cls.fullname)
def test_parse_method(self):
- m = self._method("method @Deprecated public static <T> Class<T>[][] name("
+ m = self._method("method @Deprecated public static native <T> Class<T>[][] name("
+ "Class<T[]>[][], Class<T[][][]>[][]...) throws Exception, T;")
self.assertTrue('static' in m.split)
self.assertTrue('public' in m.split)
self.assertTrue('method' in m.split)
+ self.assertTrue('native' in m.split)
self.assertTrue('deprecated' in m.split)
self.assertEquals('java.lang.Class[][]', m.typ)
self.assertEquals('name', m.name)
@@ -248,6 +249,7 @@ class V2ParserTests(unittest.TestCase):
self._method('method abstract String category() default "";', cls=cls)
self._method('method abstract boolean deepExport() default false;', cls=cls)
self._method('method abstract ViewDebug.FlagToString[] flagMapping() default {};', cls=cls)
+ self._method('method abstract ViewDebug.FlagToString[] flagMapping() default (double)java.lang.Float.NEGATIVE_INFINITY;', cls=cls)
def test_parse_string_field(self):
f = self._field('field @Deprecated public final String SOME_NAME = "value";')
@@ -286,5 +288,44 @@ class V2ParserTests(unittest.TestCase):
self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, "
+ """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""")
+ def test_kotlin_operator(self):
+ self._method('method public operator void unaryPlus(androidx.navigation.NavDestination);')
+ self._method('method public static operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);')
+ self._method('method public static operator <T> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);')
+
+ def test_kotlin_property(self):
+ self._field('property public VM value;')
+ self._field('property public final String? action;')
+
+ def test_kotlin_varargs(self):
+ self._method('method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);')
+
+ def test_kotlin_default_values(self):
+ self._method('method public void foo(String! = null, String! = "Hello World", int = 42);')
+ self._method('method void method(String, String firstArg = "hello", int secondArg = "42", String thirdArg = "world");')
+ self._method('method void method(String, String firstArg = "hello", int secondArg = "42");')
+ self._method('method void method(String, String firstArg = "hello");')
+ self._method('method void edit(android.Type, boolean commit = false, Function1<? super Editor,kotlin.Unit> action);')
+ self._method('method <K, V> LruCache<K,V> lruCache(int maxSize, Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, Function1<? extends V> create = { (V)null }, Function4<kotlin.Unit> onEntryRemoved = { _, _, _, _ -> });')
+ self._method('method android.Bitmap? drawToBitmap(android.View, android.Config config = android.graphics.Bitmap.Config.ARGB_8888);')
+ self._method('method void emptyLambda(Function0<kotlin.Unit> sizeOf = {});')
+ self._method('method void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);')
+ self._method('method void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);')
+ self._method('method void method3(String str, int p, int int2 = double(int) + str.length);')
+ self._method('method void print(test.pkg.Foo foo = test.pkg.Foo());')
+
+ def test_type_use_annotation(self):
+ self._method('method public static int codePointAt(char @NonNull [], int);')
+ self._method('method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();')
+
+ m = self._method('method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();')
+ self.assertEquals('java.lang.annotation.Annotation[]', m.typ)
+
+ m = self._method('method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();')
+ self.assertEquals('java.lang.annotation.Annotation[][]', m.typ)
+
+ m = self._method('method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);')
+ self.assertEquals('java.lang.String[]', m.typ)
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/signedconfig/prod_public.pem b/tools/signedconfig/prod_public.pem
new file mode 100644
index 000000000000..8c10215eb083
--- /dev/null
+++ b/tools/signedconfig/prod_public.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+lky6wKyGL6lE1VrD0YTMHwb0Xwc
++tzC8MvnrzVxodvTpVY/jV7V+Zktcx+pry43XPABFRXtbhTo+qykhyBA1g==
+-----END PUBLIC KEY-----
+
diff --git a/tools/signedconfig/verify_b64.sh b/tools/signedconfig/verify_b64.sh
index 8e1f58ce7b45..a4ac6a816d14 100755
--- a/tools/signedconfig/verify_b64.sh
+++ b/tools/signedconfig/verify_b64.sh
@@ -7,4 +7,30 @@
# The arg values can be taken from the debug log for SignedConfigService when verbose logging is
# enabled.
-openssl dgst -sha256 -verify $(dirname $0)/debug_public.pem -signature <(echo $2 | base64 -d) <(echo $1 | base64 -d)
+function verify() {
+ D=${1}
+ S=${2}
+ K=${3}
+ echo Trying ${K}
+ openssl dgst -sha256 -verify $(dirname $0)/${K} -signature <(echo ${S} | base64 -d) <(echo ${D} | base64 -d)
+}
+
+
+PROD_KEY_NAME=prod_public.pem
+DEBUG_KEY_NAME=debug_public.pem
+SIGNATURE="$2"
+DATA="$1"
+
+echo DATA: ${DATA}
+echo SIGNATURE: ${SIGNATURE}
+
+if verify "${DATA}" "${SIGNATURE}" "${PROD_KEY_NAME}"; then
+ echo Verified with ${PROD_KEY_NAME}
+ exit 0
+fi
+
+if verify "${DATA}" "${SIGNATURE}" "${DEBUG_KEY_NAME}"; then
+ echo Verified with ${DEBUG_KEY_NAME}
+ exit 0
+fi
+exit 1
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index af5ad512a424..840af5d5cd06 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -93,12 +93,22 @@ public class WifiInfo implements Parcelable {
private int mRssi;
/**
- * Link speed in Mbps
+ * The unit in which links speeds are expressed.
*/
public static final String LINK_SPEED_UNITS = "Mbps";
private int mLinkSpeed;
/**
+ * Tx(transmit) Link speed in Mbps
+ */
+ private int mTxLinkSpeed;
+
+ /**
+ * Rx(receive) Link speed in Mbps
+ */
+ private int mRxLinkSpeed;
+
+ /**
* Frequency in MHz
*/
public static final String FREQUENCY_UNITS = "MHz";
@@ -192,6 +202,8 @@ public class WifiInfo implements Parcelable {
setNetworkId(-1);
setRssi(INVALID_RSSI);
setLinkSpeed(-1);
+ setTxLinkSpeedMbps(-1);
+ setRxLinkSpeedMbps(-1);
setFrequency(-1);
setMeteredHint(false);
setEphemeral(false);
@@ -219,6 +231,8 @@ public class WifiInfo implements Parcelable {
mNetworkId = source.mNetworkId;
mRssi = source.mRssi;
mLinkSpeed = source.mLinkSpeed;
+ mTxLinkSpeed = source.mTxLinkSpeed;
+ mRxLinkSpeed = source.mRxLinkSpeed;
mFrequency = source.mFrequency;
mIpAddress = source.mIpAddress;
mMacAddress = source.mMacAddress;
@@ -313,7 +327,7 @@ public class WifiInfo implements Parcelable {
/**
* Returns the current link speed in {@link #LINK_SPEED_UNITS}.
- * @return the link speed.
+ * @return the link speed or -1 if there is no valid value.
* @see #LINK_SPEED_UNITS
*/
public int getLinkSpeed() {
@@ -323,7 +337,39 @@ public class WifiInfo implements Parcelable {
/** @hide */
@UnsupportedAppUsage
public void setLinkSpeed(int linkSpeed) {
- this.mLinkSpeed = linkSpeed;
+ mLinkSpeed = linkSpeed;
+ }
+
+ /**
+ * Returns the current transmit link speed in Mbps.
+ * @return the Tx link speed or -1 if there is no valid value.
+ */
+ public int getTxLinkSpeedMbps() {
+ return mTxLinkSpeed;
+ }
+
+ /**
+ * Update the last transmitted packet bit rate in Mbps.
+ * @hide
+ */
+ public void setTxLinkSpeedMbps(int txLinkSpeed) {
+ mTxLinkSpeed = txLinkSpeed;
+ }
+
+ /**
+ * Returns the current receive link speed in Mbps.
+ * @return the Rx link speed or -1 if there is no valid value.
+ */
+ public int getRxLinkSpeedMbps() {
+ return mRxLinkSpeed;
+ }
+
+ /**
+ * Update the last received packet bit rate in Mbps.
+ * @hide
+ */
+ public void setRxLinkSpeedMbps(int rxLinkSpeed) {
+ mRxLinkSpeed = rxLinkSpeed;
}
/**
@@ -529,17 +575,19 @@ public class WifiInfo implements Parcelable {
StringBuffer sb = new StringBuffer();
String none = "<none>";
- sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid).
- append(", BSSID: ").append(mBSSID == null ? none : mBSSID).
- append(", MAC: ").append(mMacAddress == null ? none : mMacAddress).
- append(", Supplicant state: ").
- append(mSupplicantState == null ? none : mSupplicantState).
- append(", RSSI: ").append(mRssi).
- append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS).
- append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS).
- append(", Net ID: ").append(mNetworkId).
- append(", Metered hint: ").append(mMeteredHint).
- append(", score: ").append(Integer.toString(score));
+ sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid)
+ .append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
+ .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
+ .append(", Supplicant state: ")
+ .append(mSupplicantState == null ? none : mSupplicantState)
+ .append(", RSSI: ").append(mRssi)
+ .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS)
+ .append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS)
+ .append(", Net ID: ").append(mNetworkId)
+ .append(", Metered hint: ").append(mMeteredHint)
+ .append(", score: ").append(Integer.toString(score));
return sb.toString();
}
@@ -553,6 +601,8 @@ public class WifiInfo implements Parcelable {
dest.writeInt(mNetworkId);
dest.writeInt(mRssi);
dest.writeInt(mLinkSpeed);
+ dest.writeInt(mTxLinkSpeed);
+ dest.writeInt(mRxLinkSpeed);
dest.writeInt(mFrequency);
if (mIpAddress != null) {
dest.writeByte((byte)1);
@@ -593,6 +643,8 @@ public class WifiInfo implements Parcelable {
info.setNetworkId(in.readInt());
info.setRssi(in.readInt());
info.setLinkSpeed(in.readInt());
+ info.setTxLinkSpeedMbps(in.readInt());
+ info.setRxLinkSpeedMbps(in.readInt());
info.setFrequency(in.readInt());
if (in.readByte() == 1) {
try {