Merge "Add CONTROL_KEYGUARD_SECURE_NOTIFICATIONS to shell app"
diff --git a/Android.bp b/Android.bp
index f4e8b63..035420f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -384,6 +384,7 @@
"core/java/android/view/IRecentsAnimationRunner.aidl",
"core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
"core/java/android/view/IRotationWatcher.aidl",
+ "core/java/android/view/ISystemGestureExclusionListener.aidl",
"core/java/android/view/IWallpaperVisibilityListener.aidl",
"core/java/android/view/IWindow.aidl",
"core/java/android/view/IWindowFocusObserver.aidl",
@@ -753,10 +754,6 @@
"android.hardware.radio-V1.2-java",
"android.hardware.radio-V1.3-java",
"android.hardware.radio-V1.4-java",
- "android.hardware.radio.config-V1.0-java",
- "android.hardware.radio.config-V1.1-java",
- "android.hardware.radio.config-V1.2-java",
- "android.hardware.radio.deprecated-V1.0-java",
"android.hardware.thermal-V1.0-java-constants",
"android.hardware.thermal-V1.0-java",
"android.hardware.thermal-V1.1-java",
@@ -771,8 +768,6 @@
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.hardware.wifi-V1.0-java-constants",
- "networkstack-aidl-framework-java",
- "netd_aidl_parcelables-java",
"devicepolicyprotosnano",
],
@@ -903,14 +898,8 @@
"core/java/android/net/INetworkStackConnector.aidl",
"core/java/android/net/INetworkStackStatusCallback.aidl",
"core/java/android/net/InitialConfigurationParcelable.aidl",
- "core/java/android/net/IpPrefixParcelable.aidl",
- "core/java/android/net/LinkAddressParcelable.aidl",
- "core/java/android/net/LinkPropertiesParcelable.aidl",
- "core/java/android/net/NetworkParcelable.aidl",
"core/java/android/net/PrivateDnsConfigParcel.aidl",
"core/java/android/net/ProvisioningConfigurationParcelable.aidl",
- "core/java/android/net/ProxyInfoParcelable.aidl",
- "core/java/android/net/RouteInfoParcelable.aidl",
"core/java/android/net/StaticIpConfigurationParcelable.aidl",
"core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
"core/java/android/net/dhcp/DhcpServingParamsParcel.aidl",
@@ -918,34 +907,65 @@
"core/java/android/net/dhcp/IDhcpServerCallbacks.aidl",
"core/java/android/net/ip/IIpClient.aidl",
"core/java/android/net/ip/IIpClientCallbacks.aidl",
+ "core/java/android/net/IIpMemoryStore.aidl",
+ "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+ "core/java/android/net/ipmemorystore/**/*.aidl",
],
+ backend: {
+ ndk: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ },
api_dir: "aidl/networkstack",
}
aidl_interface {
+ name: "ipmemorystore-aidl-interfaces",
+ local_include_dir: "core/java",
+ srcs: [
+ "core/java/android/net/IIpMemoryStore.aidl",
+ "core/java/android/net/IIpMemoryStoreCallbacks.aidl",
+ "core/java/android/net/ipmemorystore/**/*.aidl",
+ ],
+}
+
+aidl_interface {
name: "networkstack-aidl-framework",
local_include_dir: "core/java",
srcs: [
"core/java/android/net/TcpKeepalivePacketDataParcelable.aidl",
- "core/java/android/net/IIpMemoryStore.aidl",
- "core/java/android/net/ipmemorystore/**/*.aidl",
],
api_dir: "aidl/networkstack",
+ backend: {
+ java: {
+ sdk_version: "28",
+ },
+ },
+}
+
+filegroup {
+ name: "framework-annotations",
+ srcs: [
+ "core/java/android/annotation/NonNull.java",
+ "core/java/android/annotation/Nullable.java",
+ "core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
+ "core/java/android/annotation/UnsupportedAppUsage.java",
+ "core/java/com/android/internal/annotations/GuardedBy.java",
+ "core/java/com/android/internal/annotations/VisibleForTesting.java",
+ ]
}
filegroup {
name: "framework-networkstack-shared-srcs",
srcs: [
// TODO: remove these annotations as soon as we can use andoid.support.annotations.*
- "core/java/android/annotation/NonNull.java",
- "core/java/android/annotation/Nullable.java",
- "core/java/android/annotation/IntDef.java",
- "core/java/android/annotation/IntRange.java",
- "core/java/android/annotation/UnsupportedAppUsage.java",
+ ":framework-annotations",
"core/java/android/net/DhcpResults.java",
"core/java/android/util/LocalLog.java",
- "core/java/com/android/internal/annotations/GuardedBy.java",
- "core/java/com/android/internal/annotations/VisibleForTesting.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IndentingPrintWriter.java",
"core/java/com/android/internal/util/IState.java",
@@ -1132,6 +1152,7 @@
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
+ "core/java/android/annotation/UnsupportedAppUsage.java",
"core/java/android/os/HwBinder.java",
"core/java/android/os/HwBlob.java",
"core/java/android/os/HwParcel.java",
@@ -1664,6 +1685,7 @@
srcs: [
":openjdk_java_files",
":non_openjdk_java_files",
+ ":opt-telephony-common-srcs",
],
arg_files: [
"core/res/AndroidManifest.xml",
@@ -1799,4 +1821,4 @@
name: "framework-aidl-mappings",
srcs: [":framework-defaults"],
output: "framework-aidl-mappings.txt"
-}
\ No newline at end of file
+}
diff --git a/api/current.txt b/api/current.txt
index 6fdf9c3..5355dd5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4263,24 +4263,24 @@
}
public class AppOpsManager {
- method @Deprecated public int checkOp(String, int, String);
- method @Deprecated public int checkOpNoThrow(String, int, String);
- method public void checkPackage(int, String);
- method public void finishOp(String, int, String);
- method public int noteOp(String, int, String);
- method public int noteOpNoThrow(String, int, String);
- method public int noteProxyOp(String, String);
- method public int noteProxyOpNoThrow(String, String);
+ method @Deprecated public int checkOp(@NonNull String, int, @NonNull String);
+ method @Deprecated public int checkOpNoThrow(@NonNull String, int, @NonNull String);
+ method public void checkPackage(int, @NonNull String);
+ method public void finishOp(@NonNull String, int, @NonNull String);
+ method public int noteOp(@NonNull String, int, @NonNull String);
+ method public int noteOpNoThrow(@NonNull String, int, @NonNull String);
+ method public int noteProxyOp(@NonNull String, @NonNull String);
+ method public int noteProxyOpNoThrow(@NonNull String, @NonNull String);
method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
method public static String permissionToOp(String);
- method public int startOp(String, int, String);
- method public int startOpNoThrow(String, int, String);
- method public void startWatchingMode(String, String, android.app.AppOpsManager.OnOpChangedListener);
- method public void startWatchingMode(String, String, int, android.app.AppOpsManager.OnOpChangedListener);
- method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener);
- method public int unsafeCheckOp(String, int, String);
- method public int unsafeCheckOpNoThrow(String, int, String);
- method public int unsafeCheckOpRaw(@NonNull String, int, String);
+ method public int startOp(@NonNull String, int, @NonNull String);
+ method public int startOpNoThrow(@NonNull String, int, @NonNull String);
+ method public void startWatchingMode(@NonNull String, @Nullable String, @NonNull android.app.AppOpsManager.OnOpChangedListener);
+ method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
+ method public void stopWatchingMode(@NonNull android.app.AppOpsManager.OnOpChangedListener);
+ method public int unsafeCheckOp(@NonNull String, int, @NonNull String);
+ method public int unsafeCheckOpNoThrow(@NonNull String, int, @NonNull String);
+ method public int unsafeCheckOpRaw(@NonNull String, int, @NonNull String);
method public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
field public static final int MODE_ALLOWED = 0; // 0x0
field public static final int MODE_DEFAULT = 3; // 0x3
@@ -5429,7 +5429,7 @@
method @NonNull public android.app.Notification.Action.Builder addRemoteInput(android.app.RemoteInput);
method @NonNull public android.app.Notification.Action build();
method @NonNull public android.app.Notification.Action.Builder extend(android.app.Notification.Action.Extender);
- method public android.os.Bundle getExtras();
+ method @NonNull public android.os.Bundle getExtras();
method @NonNull public android.app.Notification.Action.Builder setAllowGeneratedReplies(boolean);
method @NonNull public android.app.Notification.Action.Builder setContextual(boolean);
method @NonNull public android.app.Notification.Action.Builder setSemanticAction(int);
@@ -6623,7 +6623,7 @@
method @Nullable public String[] getAccountTypesWithManagementDisabled();
method @Nullable public java.util.List<android.content.ComponentName> getActiveAdmins();
method @NonNull public java.util.Set<java.lang.String> getAffiliationIds(@NonNull android.content.ComponentName);
- method @Nullable public java.util.List<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
+ method @Nullable public java.util.Set<java.lang.String> getAlwaysOnVpnLockdownWhitelist(@NonNull android.content.ComponentName);
method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
method @WorkerThread @NonNull public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
@@ -6736,7 +6736,7 @@
method public void setAccountManagementDisabled(@NonNull android.content.ComponentName, String, boolean);
method public void setAffiliationIds(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean) throws android.content.pm.PackageManager.NameNotFoundException;
- method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.List<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public void setAlwaysOnVpnPackage(@NonNull android.content.ComponentName, @Nullable String, boolean, @Nullable java.util.Set<java.lang.String>) throws android.content.pm.PackageManager.NameNotFoundException;
method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -11051,6 +11051,7 @@
method public void dump(android.util.Printer, String);
method public static CharSequence getCategoryTitle(android.content.Context, int);
method public boolean isProfileableByShell();
+ method public boolean isResourceOverlay();
method public boolean isVirtualPreload();
method public CharSequence loadDescription(android.content.pm.PackageManager);
field public static final int CATEGORY_AUDIO = 1; // 0x1
@@ -11676,7 +11677,6 @@
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
field public static final String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
- field public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
@@ -12016,7 +12016,7 @@
method @NonNull public android.content.pm.ShortcutInfo.Builder setIntents(@NonNull android.content.Intent[]);
method @NonNull public android.content.pm.ShortcutInfo.Builder setLocusId(@NonNull android.content.LocusId);
method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLabel(@NonNull CharSequence);
- method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived();
+ method @NonNull public android.content.pm.ShortcutInfo.Builder setLongLived(boolean);
method @NonNull public android.content.pm.ShortcutInfo.Builder setPerson(@NonNull android.app.Person);
method @NonNull public android.content.pm.ShortcutInfo.Builder setPersons(@NonNull android.app.Person[]);
method @NonNull public android.content.pm.ShortcutInfo.Builder setRank(int);
@@ -15953,7 +15953,6 @@
public class MeasuredText {
method public void getBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull android.graphics.Rect);
method @FloatRange(from=0.0f) @Px public float getCharWidthAt(@IntRange(from=0) int);
- method @NonNull public char[] getChars();
method @FloatRange(from=0.0) @Px public float getWidth(@IntRange(from=0) int, @IntRange(from=0) int);
}
@@ -17367,15 +17366,16 @@
method @Nullable public java.util.Set<android.util.Size> getInputSizes(int);
method @NonNull public java.util.Set<java.lang.Integer> getOutputFormats();
method @IntRange(from=0) public long getOutputMinFrameDuration(int, @NonNull android.util.Size);
- method public <T> long getOutputMinFrameDuration(@NonNull Class<T>, @NonNull android.util.Size);
+ method @IntRange(from=0) public <T> long getOutputMinFrameDuration(@NonNull Class<T>, @NonNull android.util.Size);
method @Nullable public java.util.Set<android.util.Size> getOutputSizes(int);
- method public <T> java.util.Set<android.util.Size> getOutputSizes(@NonNull Class<T>);
+ method @Nullable public <T> java.util.Set<android.util.Size> getOutputSizes(@NonNull Class<T>);
method @IntRange(from=0) public long getOutputStallDuration(int, @NonNull android.util.Size);
- method public <T> long getOutputStallDuration(@NonNull Class<T>, @NonNull android.util.Size);
+ method @IntRange(from=0) public <T> long getOutputStallDuration(@NonNull Class<T>, @NonNull android.util.Size);
method public int getRecommendedUseCase();
method @Nullable public java.util.Set<java.lang.Integer> getValidOutputFormatsForInput(int);
method public boolean isOutputSupportedFor(int);
method public boolean isOutputSupportedFor(@NonNull android.view.Surface);
+ field public static final int USECASE_LOW_LATENCY_SNAPSHOT = 6; // 0x6
field public static final int USECASE_PREVIEW = 0; // 0x0
field public static final int USECASE_RAW = 5; // 0x5
field public static final int USECASE_RECORD = 1; // 0x1
@@ -22810,6 +22810,7 @@
field public static final int CONSTELLATION_GALILEO = 6; // 0x6
field public static final int CONSTELLATION_GLONASS = 3; // 0x3
field public static final int CONSTELLATION_GPS = 1; // 0x1
+ field public static final int CONSTELLATION_IRNSS = 7; // 0x7
field public static final int CONSTELLATION_QZSS = 4; // 0x4
field public static final int CONSTELLATION_SBAS = 2; // 0x2
field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
@@ -22966,6 +22967,7 @@
method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
+ field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
field public static final String GPS_PROVIDER = "gps";
field public static final String KEY_LOCATION_CHANGED = "location";
field public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
@@ -23005,7 +23007,7 @@
method protected abstract String onGetSummary();
method public final void onStart(android.content.Intent, int);
method public final int onStartCommand(android.content.Intent, int, int);
- method public static final void refreshSettings(android.content.Context);
+ method public static final void refreshSettings(@NonNull android.content.Context);
field public static final String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
field public static final String ACTION_SERVICE_INTENT = "android.location.SettingInjectorService";
field public static final String ATTRIBUTES_NAME = "injected-location-setting";
@@ -23293,6 +23295,7 @@
field public static final String ACTION_MICROPHONE_MUTE_CHANGED = "android.media.action.MICROPHONE_MUTE_CHANGED";
field @Deprecated public static final String ACTION_SCO_AUDIO_STATE_CHANGED = "android.media.SCO_AUDIO_STATE_CHANGED";
field public static final String ACTION_SCO_AUDIO_STATE_UPDATED = "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
+ field public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = "android.media.action.SPEAKERPHONE_STATE_CHANGED";
field public static final int ADJUST_LOWER = -1; // 0xffffffff
field public static final int ADJUST_MUTE = -100; // 0xffffff9c
field public static final int ADJUST_RAISE = 1; // 0x1
@@ -23398,15 +23401,16 @@
}
public final class AudioPlaybackCaptureConfiguration {
+ method @NonNull public android.media.projection.MediaProjection getMediaProjection();
}
public static final class AudioPlaybackCaptureConfiguration.Builder {
ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection);
method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
- method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes);
+ method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(int);
method @NonNull public android.media.AudioPlaybackCaptureConfiguration build();
method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int);
- method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(@NonNull android.media.AudioAttributes);
+ method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(int);
}
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
@@ -24423,9 +24427,10 @@
field public static final int AV1Level71 = 2097152; // 0x200000
field public static final int AV1Level72 = 4194304; // 0x400000
field public static final int AV1Level73 = 8388608; // 0x800000
- field public static final int AV1Profile0 = 1; // 0x1
- field public static final int AV1Profile1 = 2; // 0x2
- field public static final int AV1Profile2 = 4; // 0x4
+ field public static final int AV1ProfileMain10 = 2; // 0x2
+ field public static final int AV1ProfileMain10HDR10 = 4096; // 0x1000
+ field public static final int AV1ProfileMain10HDR10Plus = 8192; // 0x2000
+ field public static final int AV1ProfileMain8 = 1; // 0x1
field public static final int AVCLevel1 = 1; // 0x1
field public static final int AVCLevel11 = 4; // 0x4
field public static final int AVCLevel12 = 8; // 0x8
@@ -24619,42 +24624,39 @@
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int);
method public boolean covers(@NonNull android.media.MediaFormat);
method public boolean covers(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint);
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
- field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
- field public final int frameRate;
- field public final long macroBlockRate;
- field public final int macroBlocks;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
+ field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
}
public final class MediaCodecList {
@@ -25081,6 +25083,7 @@
field public static final String KEY_LANGUAGE = "language";
field public static final String KEY_LATENCY = "latency";
field public static final String KEY_LEVEL = "level";
+ field public static final String KEY_MAX_BFRAMES = "max-bframes";
field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
field public static final String KEY_MAX_HEIGHT = "max-height";
field public static final String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -25697,14 +25700,14 @@
public static class MediaPlayer2.DrmEventCallback {
ctor public MediaPlayer2.DrmEventCallback();
method public void onDrmConfig(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm);
- method public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(android.media.MediaPlayer2, android.media.DataSourceDesc, android.media.MediaPlayer2.DrmInfo);
- method public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
+ method @Nullable public android.media.MediaPlayer2.DrmPreparationInfo onDrmInfo(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaPlayer2.DrmInfo);
+ method @NonNull public byte[] onDrmKeyRequest(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, @NonNull android.media.MediaDrm.KeyRequest);
method public void onDrmPrepared(@NonNull android.media.MediaPlayer2, @NonNull android.media.DataSourceDesc, int, @Nullable byte[]);
}
public static final class MediaPlayer2.DrmInfo {
- method public java.util.Map<java.util.UUID,byte[]> getPssh();
- method public java.util.List<java.util.UUID> getSupportedSchemes();
+ method @NonNull public java.util.Map<java.util.UUID,byte[]> getPssh();
+ method @NonNull public java.util.List<java.util.UUID> getSupportedSchemes();
}
public static final class MediaPlayer2.DrmPreparationInfo {
@@ -25712,13 +25715,13 @@
public static final class MediaPlayer2.DrmPreparationInfo.Builder {
ctor public MediaPlayer2.DrmPreparationInfo.Builder();
- method public android.media.MediaPlayer2.DrmPreparationInfo build();
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
- method public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo build();
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setInitData(@Nullable byte[]);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeySetId(@Nullable byte[]);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setKeyType(int);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setMimeType(@Nullable String);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setOptionalParameters(@Nullable java.util.Map<java.lang.String,java.lang.String>);
+ method @NonNull public android.media.MediaPlayer2.DrmPreparationInfo.Builder setUuid(@NonNull java.util.UUID);
}
public static class MediaPlayer2.EventCallback {
@@ -25749,7 +25752,7 @@
}
public static final class MediaPlayer2.NoDrmSchemeException extends android.media.MediaDrmException {
- ctor public MediaPlayer2.NoDrmSchemeException(String);
+ ctor public MediaPlayer2.NoDrmSchemeException(@Nullable String);
}
public static class MediaPlayer2.TrackInfo {
@@ -26139,10 +26142,11 @@
}
public final class MediaTimestamp {
+ ctor public MediaTimestamp(long, long, @FloatRange(from=0.0f, to=java.lang.Float.MAX_VALUE) float);
method public long getAnchorMediaTimeUs();
method public long getAnchorSystemNanoTime();
method @Deprecated public long getAnchorSytemNanoTime();
- method public float getMediaClockRate();
+ method @FloatRange(from=0.0f, to=java.lang.Float.MAX_VALUE) public float getMediaClockRate();
field public static final android.media.MediaTimestamp TIMESTAMP_UNKNOWN;
}
@@ -26470,6 +26474,7 @@
}
public final class SubtitleData {
+ ctor public SubtitleData(int, long, long, @NonNull byte[]);
method @NonNull public byte[] getData();
method public long getDurationUs();
method public long getStartTimeUs();
@@ -26510,6 +26515,7 @@
}
public final class TimedMetaData {
+ ctor public TimedMetaData(long, @NonNull byte[]);
method public byte[] getMetaData();
method public long getTimestamp();
}
@@ -28756,10 +28762,9 @@
}
public final class DnsResolver {
- method public static android.net.DnsResolver getInstance();
- method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
- method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.RawAnswerListener) throws android.system.ErrnoException;
- method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull android.os.Handler, @NonNull android.net.DnsResolver.InetAddressAnswerListener) throws android.system.ErrnoException;
+ method @NonNull public static android.net.DnsResolver getInstance();
+ method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+ method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback<T>);
field public static final int CLASS_IN = 1; // 0x1
field public static final int FLAG_EMPTY = 0; // 0x0
field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -28769,12 +28774,23 @@
field public static final int TYPE_AAAA = 28; // 0x1c
}
- public static interface DnsResolver.InetAddressAnswerListener {
- method public void onAnswer(@NonNull java.util.List<java.net.InetAddress>);
+ public abstract static class DnsResolver.AnswerCallback<T> {
+ ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>);
+ method public abstract void onAnswer(@NonNull T);
+ method public abstract void onParseException(@NonNull android.net.ParseException);
+ method public abstract void onQueryException(@NonNull android.system.ErrnoException);
}
- public static interface DnsResolver.RawAnswerListener {
- method public void onAnswer(@Nullable byte[]);
+ public static interface DnsResolver.AnswerParser<T> {
+ method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException;
+ }
+
+ public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> {
+ ctor public DnsResolver.InetAddressAnswerCallback();
+ }
+
+ public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> {
+ ctor public DnsResolver.RawAnswerCallback();
}
public class InetAddresses {
@@ -29089,6 +29105,8 @@
}
public class ParseException extends java.lang.RuntimeException {
+ ctor public ParseException(@NonNull String);
+ ctor public ParseException(@NonNull String, @NonNull Throwable);
field public String response;
}
@@ -30303,13 +30321,11 @@
}
public static final class WifiAwareNetworkSpecifier.Builder {
- ctor public WifiAwareNetworkSpecifier.Builder();
+ ctor public WifiAwareNetworkSpecifier.Builder(@NonNull android.net.wifi.aware.DiscoverySession, @NonNull android.net.wifi.aware.PeerHandle);
method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier build();
- method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
- method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
- method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(int);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(@IntRange(from=0, to=65535) int);
method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPskPassphrase(@NonNull String);
- method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(int);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(@IntRange(from=0, to=255) int);
}
public class WifiAwareSession implements java.lang.AutoCloseable {
@@ -39006,10 +39022,12 @@
method public static long getLong(android.content.ContentResolver, String) throws android.provider.Settings.SettingNotFoundException;
method public static String getString(android.content.ContentResolver, String);
method public static android.net.Uri getUriFor(String);
+ method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
method public static boolean putFloat(android.content.ContentResolver, String, float);
method public static boolean putInt(android.content.ContentResolver, String, int);
method public static boolean putLong(android.content.ContentResolver, String, long);
method public static boolean putString(android.content.ContentResolver, String, String);
+ method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
field public static final String ACCESSIBILITY_DISPLAY_INVERSION_ENABLED = "accessibility_display_inversion_enabled";
field public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
field @Deprecated public static final String ACCESSIBILITY_SPEAK_PASSWORD = "speak_password";
@@ -42483,12 +42501,12 @@
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(String, int) throws android.system.ErrnoException;
method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
- method public static void bind(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+ method public static void bind(@NonNull java.io.FileDescriptor, @NonNull java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static void chmod(String, int) throws android.system.ErrnoException;
method public static void chown(String, int, int) throws android.system.ErrnoException;
method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException;
method public static void connect(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
- method public static void connect(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+ method public static void connect(@NonNull java.io.FileDescriptor, @NonNull java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static java.io.FileDescriptor dup(java.io.FileDescriptor) throws android.system.ErrnoException;
method public static java.io.FileDescriptor dup2(java.io.FileDescriptor, int) throws android.system.ErrnoException;
method public static String[] environ();
@@ -42553,7 +42571,7 @@
method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
- method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
+ method public static int sendto(@NonNull java.io.FileDescriptor, @NonNull byte[], int, int, int, @Nullable java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method @Deprecated public static void setegid(int) throws android.system.ErrnoException;
method public static void setenv(String, String, boolean) throws android.system.ErrnoException;
method @Deprecated public static void seteuid(int) throws android.system.ErrnoException;
@@ -43189,6 +43207,7 @@
method public void unregisterCallback(android.telecom.Call.Callback);
field @Deprecated public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
field public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
+ field public static final String EXTRA_SILENT_RINGING_REQUESTED = "android.telecom.extra.SILENT_RINGING_REQUESTED";
field public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS";
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_CONNECTING = 9; // 0x9
@@ -43347,9 +43366,9 @@
public abstract class CallRedirectionService extends android.app.Service {
ctor public CallRedirectionService();
method public final void cancelCall();
- method public final android.os.IBinder onBind(android.content.Intent);
+ method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onPlaceCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
- method public final boolean onUnbind(android.content.Intent);
+ method public final boolean onUnbind(@NonNull android.content.Intent);
method public final void placeCallUnmodified();
method public final void redirectCall(@NonNull android.net.Uri, @NonNull android.telecom.PhoneAccountHandle, boolean);
field public static final String SERVICE_INTERFACE = "android.telecom.CallRedirectionService";
@@ -43376,6 +43395,7 @@
public static class CallScreeningService.CallResponse {
method public boolean getDisallowCall();
method public boolean getRejectCall();
+ method public boolean getSilenceCall();
method public boolean getSkipCallLog();
method public boolean getSkipNotification();
}
@@ -43385,6 +43405,7 @@
method public android.telecom.CallScreeningService.CallResponse build();
method public android.telecom.CallScreeningService.CallResponse.Builder setDisallowCall(boolean);
method public android.telecom.CallScreeningService.CallResponse.Builder setRejectCall(boolean);
+ method @NonNull public android.telecom.CallScreeningService.CallResponse.Builder setSilenceCall(boolean);
method public android.telecom.CallScreeningService.CallResponse.Builder setSkipCallLog(boolean);
method public android.telecom.CallScreeningService.CallResponse.Builder setSkipNotification(boolean);
}
@@ -45043,7 +45064,6 @@
method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
method public void setSubscriptionOverrideCongested(int, boolean, long);
@@ -45177,7 +45197,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isMultisimSupported();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
method public boolean isNetworkRoaming();
method public boolean isRttSupported();
method public boolean isSmsCapable();
@@ -45242,7 +45262,7 @@
field public static final String EXTRA_CARRIER_ID = "android.telephony.extra.CARRIER_ID";
field public static final String EXTRA_CARRIER_NAME = "android.telephony.extra.CARRIER_NAME";
field public static final String EXTRA_HIDE_PUBLIC_SETTINGS = "android.telephony.extra.HIDE_PUBLIC_SETTINGS";
- field public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
+ field @Deprecated public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
field public static final String EXTRA_IS_REFRESH = "android.telephony.extra.IS_REFRESH";
field public static final String EXTRA_LAUNCH_VOICEMAIL_SETTINGS_INTENT = "android.telephony.extra.LAUNCH_VOICEMAIL_SETTINGS_INTENT";
field public static final String EXTRA_NETWORK_COUNTRY = "android.telephony.extra.NETWORK_COUNTRY";
@@ -45257,6 +45277,9 @@
field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
field public static final String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
field public static final String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
+ field public static final int MULTISIM_ALLOWED = 0; // 0x0
+ field public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2; // 0x2
+ field public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1; // 0x1
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
field public static final int NETWORK_TYPE_EDGE = 2; // 0x2
@@ -45281,7 +45304,7 @@
field public static final int PHONE_TYPE_GSM = 1; // 0x1
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
- field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+ field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
field public static final int SIM_STATE_ABSENT = 1; // 0x1
@@ -45554,7 +45577,7 @@
method public boolean isEnabled();
method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
- method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, String, android.app.PendingIntent);
+ method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
@@ -50425,6 +50448,7 @@
method protected float getLeftFadingEdgeStrength();
method protected int getLeftPaddingOffset();
method public final boolean getLocalVisibleRect(android.graphics.Rect);
+ method public void getLocationInSurface(@NonNull @Size(2) int[]);
method public void getLocationInWindow(@Size(2) int[]);
method public void getLocationOnScreen(@Size(2) int[]);
method public android.graphics.Matrix getMatrix();
@@ -51938,6 +51962,7 @@
method @NonNull public android.view.WindowInsets consumeStableInsets();
method @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
method @Nullable public android.view.DisplayCutout getDisplayCutout();
+ method @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
method public int getStableInsetBottom();
method public int getStableInsetLeft();
method public int getStableInsetRight();
@@ -51949,6 +51974,7 @@
method public int getSystemWindowInsetRight();
method public int getSystemWindowInsetTop();
method @NonNull public android.graphics.Insets getSystemWindowInsets();
+ method @NonNull public android.graphics.Insets getTappableElementInsets();
method public boolean hasInsets();
method public boolean hasStableInsets();
method public boolean hasSystemWindowInsets();
@@ -51964,9 +51990,11 @@
ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
method @NonNull public android.view.WindowInsets build();
method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+ method @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setStableInsets(@NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setSystemGestureInsets(@NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setSystemWindowInsets(@NonNull android.graphics.Insets);
+ method @NonNull public android.view.WindowInsets.Builder setTappableElementInsets(@NonNull android.graphics.Insets);
}
public interface WindowManager extends android.view.ViewManager {
@@ -53011,7 +53039,7 @@
method public int describeContents();
method @NonNull public static android.view.contentcapture.ContentCaptureContext forLocusId(@NonNull String);
method @Nullable public android.os.Bundle getExtras();
- method @NonNull public android.content.LocusId getLocusId();
+ method @Nullable public android.content.LocusId getLocusId();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.contentcapture.ContentCaptureContext> CREATOR;
}
@@ -53478,7 +53506,6 @@
package android.view.inspector {
public interface InspectionCompanion<T> {
- method @Nullable public default String getNodeName();
method public void mapProperties(@NonNull android.view.inspector.PropertyMapper);
method public void readProperties(@NonNull T, @NonNull android.view.inspector.PropertyReader);
}
@@ -53491,27 +53518,12 @@
method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
}
- public final class IntEnumMapping {
- method @Nullable public String get(int);
- }
-
- public static final class IntEnumMapping.Builder {
- ctor public IntEnumMapping.Builder();
- method @NonNull public android.view.inspector.IntEnumMapping.Builder addValue(@NonNull String, int);
- method @NonNull public android.view.inspector.IntEnumMapping build();
- }
-
public final class IntFlagMapping {
+ ctor public IntFlagMapping();
+ method public void add(int, int, @NonNull String);
method @NonNull public java.util.Set<java.lang.String> get(int);
}
- public static final class IntFlagMapping.Builder {
- ctor public IntFlagMapping.Builder();
- method @NonNull public android.view.inspector.IntFlagMapping.Builder addFlag(@NonNull String, int);
- method @NonNull public android.view.inspector.IntFlagMapping.Builder addFlag(@NonNull String, int, int);
- method @NonNull public android.view.inspector.IntFlagMapping build();
- }
-
public interface PropertyMapper {
method public int mapBoolean(@NonNull String, @AttrRes int);
method public int mapByte(@NonNull String, @AttrRes int);
@@ -53521,8 +53533,8 @@
method public int mapFloat(@NonNull String, @AttrRes int);
method public int mapGravity(@NonNull String, @AttrRes int);
method public int mapInt(@NonNull String, @AttrRes int);
- method public int mapIntEnum(@NonNull String, @AttrRes int, @NonNull android.view.inspector.IntEnumMapping);
- method public int mapIntFlag(@NonNull String, @AttrRes int, @NonNull android.view.inspector.IntFlagMapping);
+ method public int mapIntEnum(@NonNull String, @AttrRes int, @NonNull java.util.function.IntFunction<java.lang.String>);
+ method public int mapIntFlag(@NonNull String, @AttrRes int, @NonNull java.util.function.IntFunction<java.util.Set<java.lang.String>>);
method public int mapLong(@NonNull String, @AttrRes int);
method public int mapObject(@NonNull String, @AttrRes int);
method public int mapResourceId(@NonNull String, @AttrRes int);
diff --git a/api/removed.txt b/api/removed.txt
index 5108dd0..fa07094 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -314,17 +314,11 @@
package android.net {
public class ConnectivityManager {
- method @Deprecated public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler);
method @Deprecated public boolean requestRouteToHost(int, int);
method @Deprecated public int startUsingNetworkFeature(int, String);
method @Deprecated public int stopUsingNetworkFeature(int, String);
}
- @Deprecated public abstract static class ConnectivityManager.TetheringEntitlementValueListener {
- ctor public ConnectivityManager.TetheringEntitlementValueListener();
- method public void onEntitlementResult(int);
- }
-
@Deprecated public class NetworkBadging {
method @NonNull public static android.graphics.drawable.Drawable getWifiIcon(@IntRange(from=0, to=4) int, int, @Nullable android.content.res.Resources.Theme);
field public static final int BADGING_4K = 30; // 0x1e
@@ -553,11 +547,6 @@
field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
}
- public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
- method @Deprecated public static boolean isLocationProviderEnabled(android.content.ContentResolver, String);
- method @Deprecated public static void setLocationProviderEnabled(android.content.ContentResolver, String, boolean);
- }
-
public static final class Settings.System extends android.provider.Settings.NameValueTable {
field public static final String APPEND_FOR_LAST_AUDIBLE = "_last_audible";
field public static final String VOLUME_ALARM = "volume_alarm";
diff --git a/api/system-current.txt b/api/system-current.txt
index 42b8a5d..3e4ccb5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -186,6 +186,7 @@
field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
+ field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
field public static final String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
@@ -312,7 +313,7 @@
public class AppOpsManager {
method @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static String[] getOpStrs();
- method @Deprecated @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, String, int[]);
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable int[]);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable java.lang.String...);
method @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getPackagesForOps(@Nullable String[]);
method public static int opToDefaultMode(@NonNull String);
@@ -338,6 +339,7 @@
field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
field public static final String OPSTR_GPS = "android:gps";
field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+ field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -465,7 +467,7 @@
public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
method public int describeContents();
- method public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
+ method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
method @NonNull public String getPackageName();
method public int getUid();
method public void writeToParcel(android.os.Parcel, int);
@@ -545,11 +547,10 @@
}
public class NotificationManager {
+ method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities();
method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
- method @Nullable public android.content.ComponentName getAllowedNotificationAssistantForUser(@NonNull android.os.UserHandle);
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
- method public void setNotificationAssistantAccessGrantedForUser(@Nullable android.content.ComponentName, @NonNull android.os.UserHandle, boolean);
}
public final class StatsManager {
@@ -667,7 +668,6 @@
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedAccessibilityServices(int);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<java.lang.String> getPermittedInputMethodsForCurrentUser();
method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
- method @Nullable @RequiresPermission(value=android.Manifest.permission.INTERACT_ACROSS_USERS, conditional=true) public android.content.ComponentName getProfileOwnerAsUser(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState();
method public boolean isDeviceManaged();
@@ -745,7 +745,8 @@
method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.ComponentName getCurrentTransportComponent();
method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getDataManagementIntent(String);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public CharSequence getDataManagementIntentLabel(@NonNull String);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public String getDataManagementLabel(@NonNull String);
method @RequiresPermission(android.Manifest.permission.BACKUP) public String getDestinationString(String);
method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isAppEligibleForBackup(String);
method @RequiresPermission(android.Manifest.permission.BACKUP) public boolean isBackupEnabled();
@@ -759,7 +760,8 @@
method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAncestralSerialNumber(long);
method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAutoRestore(boolean);
method @RequiresPermission(android.Manifest.permission.BACKUP) public void setBackupEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(android.content.ComponentName, String, @Nullable android.content.Intent, String, @Nullable android.content.Intent, @Nullable String);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable String);
+ method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(@NonNull android.content.ComponentName, @NonNull String, @Nullable android.content.Intent, @NonNull String, @Nullable android.content.Intent, @Nullable CharSequence);
field public static final int ERROR_AGENT_FAILURE = -1003; // 0xfffffc15
field public static final int ERROR_BACKUP_CANCELLED = -2003; // 0xfffff82d
field public static final int ERROR_BACKUP_NOT_ALLOWED = -2001; // 0xfffff82f
@@ -864,7 +866,8 @@
method public android.content.Intent configurationIntent();
method public String currentDestinationString();
method public android.content.Intent dataManagementIntent();
- method public String dataManagementLabel();
+ method @Nullable public CharSequence dataManagementIntentLabel();
+ method @Deprecated @Nullable public String dataManagementLabel();
method public int finishBackup();
method public void finishRestore();
method public android.app.backup.RestoreSet[] getAvailableRestoreSets();
@@ -926,8 +929,10 @@
method public int restoreAll(long, android.app.backup.RestoreObserver);
method public int restorePackage(String, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
method public int restorePackage(String, android.app.backup.RestoreObserver);
- method public int restoreSome(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor, String[]);
- method public int restoreSome(long, android.app.backup.RestoreObserver, String[]);
+ method public int restorePackages(long, @Nullable android.app.backup.RestoreObserver, @NonNull java.util.Set<java.lang.String>, @Nullable android.app.backup.BackupManagerMonitor);
+ method public int restorePackages(long, @Nullable android.app.backup.RestoreObserver, @NonNull java.util.Set<java.lang.String>);
+ method @Deprecated public int restoreSome(long, android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor, String[]);
+ method @Deprecated public int restoreSome(long, android.app.backup.RestoreObserver, String[]);
}
public class RestoreSet implements android.os.Parcelable {
@@ -1199,6 +1204,7 @@
method public int getUsageSource();
method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @Nullable android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], @NonNull java.time.Duration, @NonNull java.time.Duration, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String, long);
@@ -1478,6 +1484,7 @@
}
public class OverlayManager {
+ method @Nullable public android.content.om.OverlayInfo getOverlayInfo(@NonNull String, @NonNull android.os.UserHandle);
method public java.util.List<android.content.om.OverlayInfo> getOverlayInfosForTarget(@Nullable String, int);
method public boolean setEnabled(@Nullable String, boolean, int);
method public boolean setEnabledExclusiveInCategory(@Nullable String, int);
@@ -1647,6 +1654,7 @@
field public static final String FEATURE_BROADCAST_RADIO = "android.hardware.broadcastradio";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
+ field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
@@ -1717,7 +1725,7 @@
method public void onPermissionsChanged(int);
}
- @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
+ @IntDef(prefix={"FLAG_PERMISSION_"}, value={android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET, android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE, android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED, android.content.pm.PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED, android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface PackageManager.PermissionFlags {
}
public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
@@ -1836,9 +1844,9 @@
}
public final class RollbackManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
field public static final int STATUS_FAILURE = 1; // 0x1
@@ -3066,6 +3074,19 @@
method public void onLocationBatch(java.util.List<android.location.Location>);
}
+ public final class GnssCapabilities {
+ method public boolean hasCapability(int);
+ field public static final int GEOFENCING = 2; // 0x2
+ field public static final int LOW_POWER_MODE = 0; // 0x0
+ field public static final int MEASUREMENTS = 3; // 0x3
+ field public static final int MEASUREMENT_CORRECTIONS = 5; // 0x5
+ field public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 7; // 0x7
+ field public static final int MEASUREMENT_CORRECTIONS_LOS_SATS = 6; // 0x6
+ field public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 8; // 0x8
+ field public static final int NAV_MESSAGES = 4; // 0x4
+ field public static final int SATELLITE_BLACKLIST = 1; // 0x1
+ }
+
public final class GnssMeasurementCorrections implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=-1000.0F, to=10000.0f) public double getAltitudeMeters();
@@ -3373,7 +3394,7 @@
public class LocationManager {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
- method public int getGnssCapabilities();
+ method @Nullable public android.location.GnssCapabilities getGnssCapabilities();
method @Nullable public String getLocationControllerExtraPackage();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
method public boolean isLocationControllerExtraPackageEnabled();
@@ -3557,13 +3578,6 @@
field public static final int RADIO_TUNER = 1998; // 0x7ce
}
- public static final class MediaTimestamp.Builder {
- ctor public MediaTimestamp.Builder();
- ctor public MediaTimestamp.Builder(@NonNull android.media.MediaTimestamp);
- method @NonNull public android.media.MediaTimestamp build();
- method @NonNull public android.media.MediaTimestamp.Builder setMediaTimestamp(long, long, float);
- }
-
public class PlayerProxy {
method public void pause();
method public void setPan(float);
@@ -3573,20 +3587,6 @@
method public void stop();
}
- public static final class SubtitleData.Builder {
- ctor public SubtitleData.Builder();
- ctor public SubtitleData.Builder(@NonNull android.media.SubtitleData);
- method @NonNull public android.media.SubtitleData build();
- method @NonNull public android.media.SubtitleData.Builder setSubtitleData(int, long, long, @NonNull byte[]);
- }
-
- public static final class TimedMetaData.Builder {
- ctor public TimedMetaData.Builder();
- ctor public TimedMetaData.Builder(@NonNull android.media.TimedMetaData);
- method @NonNull public android.media.TimedMetaData build();
- method @NonNull public android.media.TimedMetaData.Builder setTimedMetaData(long, @NonNull byte[]);
- }
-
}
package android.media.audiopolicy {
@@ -4027,8 +4027,8 @@
package android.net {
public class CaptivePortal implements android.os.Parcelable {
- ctor public CaptivePortal(android.os.IBinder);
- method public void logEvent(int, String);
+ ctor public CaptivePortal(@NonNull android.os.IBinder);
+ method public void logEvent(int, @NonNull String);
method public void useNetwork();
field public static final int APP_RETURN_DISMISSED = 0; // 0x0
field public static final int APP_RETURN_UNWANTED = 1; // 0x1
@@ -4235,18 +4235,18 @@
public final class StaticIpConfiguration implements android.os.Parcelable {
ctor public StaticIpConfiguration();
- ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
- method public void addDnsServer(java.net.InetAddress);
+ ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ method public void addDnsServer(@NonNull java.net.InetAddress);
method public void clear();
method public int describeContents();
- method public java.util.List<java.net.InetAddress> getDnsServers();
- method public String getDomains();
- method public java.net.InetAddress getGateway();
- method public android.net.LinkAddress getIpAddress();
- method public java.util.List<android.net.RouteInfo> getRoutes(String);
- method public void setDomains(String);
- method public void setGateway(java.net.InetAddress);
- method public void setIpAddress(android.net.LinkAddress);
+ method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+ method @Nullable public String getDomains();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @Nullable public android.net.LinkAddress getIpAddress();
+ method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(String);
+ method public void setDomains(@Nullable String);
+ method public void setGateway(@Nullable java.net.InetAddress);
+ method public void setIpAddress(@Nullable android.net.LinkAddress);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
}
@@ -4281,11 +4281,14 @@
package android.net.apf {
- public class ApfCapabilities {
+ public final class ApfCapabilities implements android.os.Parcelable {
ctor public ApfCapabilities(int, int, int);
+ method public int describeContents();
method public static boolean getApfDrop8023Frames(android.content.Context);
method public static int[] getApfEthTypeBlackList(android.content.Context);
method public boolean hasDataAccess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
field public final int apfPacketFormat;
field public final int apfVersionSupported;
field public final int maximumApfProgramSize;
@@ -4297,28 +4300,28 @@
public final class CaptivePortalProbeResult {
ctor public CaptivePortalProbeResult(int);
- ctor public CaptivePortalProbeResult(int, String, String);
- ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+ ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String);
+ ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String, @Nullable android.net.captiveportal.CaptivePortalProbeSpec);
method public boolean isFailed();
method public boolean isPartialConnectivity();
method public boolean isPortal();
method public boolean isSuccessful();
- field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+ field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
field public static final int FAILED_CODE = 599; // 0x257
field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
field public static final int PORTAL_CODE = 302; // 0x12e
- field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
+ field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
field public static final int SUCCESS_CODE = 204; // 0xcc
- field public final String detectUrl;
+ field @Nullable public final String detectUrl;
field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
- field public final String redirectUrl;
+ field @Nullable public final String redirectUrl;
}
public abstract class CaptivePortalProbeSpec {
- method public String getEncodedSpec();
- method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
- method public java.net.URL getUrl();
- method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String);
+ method @NonNull public String getEncodedSpec();
+ method @NonNull public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
+ method @NonNull public java.net.URL getUrl();
+ method @NonNull public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(@NonNull String);
method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
}
@@ -4329,78 +4332,78 @@
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
}
- public static class ApfProgramEvent.Builder {
+ public static final class ApfProgramEvent.Builder {
ctor public ApfProgramEvent.Builder();
- method public android.net.metrics.ApfProgramEvent build();
- method public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
- method public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
- method public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
- method public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
- method public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
- method public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+ method @NonNull public android.net.metrics.ApfProgramEvent build();
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
}
public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
}
- public static class ApfStats.Builder {
+ public static final class ApfStats.Builder {
ctor public ApfStats.Builder();
- method public android.net.metrics.ApfStats build();
- method public android.net.metrics.ApfStats.Builder setDroppedRas(int);
- method public android.net.metrics.ApfStats.Builder setDurationMs(long);
- method public android.net.metrics.ApfStats.Builder setMatchingRas(int);
- method public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
- method public android.net.metrics.ApfStats.Builder setParseErrors(int);
- method public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
- method public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
- method public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
- method public android.net.metrics.ApfStats.Builder setReceivedRas(int);
- method public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+ method @NonNull public android.net.metrics.ApfStats build();
+ method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
+ method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
}
public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
}
- public static class DhcpClientEvent.Builder {
+ public static final class DhcpClientEvent.Builder {
ctor public DhcpClientEvent.Builder();
- method public android.net.metrics.DhcpClientEvent build();
- method public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
- method public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+ method @NonNull public android.net.metrics.DhcpClientEvent build();
+ method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+ method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
}
public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
ctor public DhcpErrorEvent(int);
method public static int errorCodeWithOption(int, int);
- field public static final int BOOTP_TOO_SHORT;
- field public static final int BUFFER_UNDERFLOW;
- field public static final int DHCP_BAD_MAGIC_COOKIE;
+ field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
+ field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
+ field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
field public static final int DHCP_ERROR = 4; // 0x4
- field public static final int DHCP_INVALID_OPTION_LENGTH;
- field public static final int DHCP_NO_COOKIE;
- field public static final int DHCP_NO_MSG_TYPE;
- field public static final int DHCP_UNKNOWN_MSG_TYPE;
+ field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
+ field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
+ field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
+ field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
field public static final int L2_ERROR = 1; // 0x1
- field public static final int L2_TOO_SHORT;
- field public static final int L2_WRONG_ETH_TYPE;
+ field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
+ field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
field public static final int L3_ERROR = 2; // 0x2
- field public static final int L3_INVALID_IP;
- field public static final int L3_NOT_IPV4;
- field public static final int L3_TOO_SHORT;
+ field public static final int L3_INVALID_IP = 33751040; // 0x2030000
+ field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
+ field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
field public static final int L4_ERROR = 3; // 0x3
- field public static final int L4_NOT_UDP;
- field public static final int L4_WRONG_PORT;
+ field public static final int L4_NOT_UDP = 50397184; // 0x3010000
+ field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
field public static final int MISC_ERROR = 5; // 0x5
- field public static final int PARSING_ERROR;
- field public static final int RECEIVE_ERROR;
+ field public static final int PARSING_ERROR = 84082688; // 0x5030000
+ field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
}
public class IpConnectivityLog {
ctor public IpConnectivityLog();
- method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(int, int[], android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
}
public static interface IpConnectivityLog.Event extends android.os.Parcelable {
@@ -4471,28 +4474,28 @@
field public static final int PROBE_PRIVDNS = 5; // 0x5
}
- public static class ValidationProbeEvent.Builder {
+ public static final class ValidationProbeEvent.Builder {
ctor public ValidationProbeEvent.Builder();
- method public android.net.metrics.ValidationProbeEvent build();
- method public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
- method public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
- method public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+ method @NonNull public android.net.metrics.ValidationProbeEvent build();
+ method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+ method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+ method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
}
}
package android.net.util {
- public class SocketUtils {
+ public final class SocketUtils {
method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
- method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
- method public static java.net.SocketAddress makePacketSocketAddress(short, int);
- method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+ method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
@@ -4933,6 +4936,10 @@
public final class WifiUsabilityStatsEntry implements android.os.Parcelable {
method public int describeContents();
+ method public int getCellularDataNetworkType();
+ method public int getCellularSignalStrengthDb();
+ method public int getCellularSignalStrengthDbm();
+ method public boolean getIsSameRegisteredCell();
method public int getLinkSpeedMbps();
method public int getProbeElapsedTimeSinceLastUpdateMillis();
method public int getProbeMcsRateSinceLastUpdate();
@@ -5485,7 +5492,7 @@
}
public class ServiceSpecificException extends java.lang.RuntimeException {
- ctor public ServiceSpecificException(int, String);
+ ctor public ServiceSpecificException(int, @Nullable String);
ctor public ServiceSpecificException(int);
field public final int errorCode;
}
@@ -5604,7 +5611,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
- method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.graphics.Bitmap getUserIcon();
+ method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public android.graphics.Bitmap getUserIcon();
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
@@ -5615,6 +5622,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
@@ -5859,6 +5867,7 @@
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot";
+ field public static final String NAMESPACE_APP_COMPAT = "app_compat";
field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
@@ -5869,10 +5878,15 @@
field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+ field public static final String NAMESPACE_ROLLBACK = "rollback";
+ field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
field public static final String NAMESPACE_RUNTIME = "runtime";
field public static final String NAMESPACE_RUNTIME_NATIVE = "runtime_native";
field public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
+ field public static final String NAMESPACE_SCHEDULER = "scheduler";
+ field public static final String NAMESPACE_STORAGE = "storage";
field public static final String NAMESPACE_SYSTEMUI = "systemui";
+ field public static final String NAMESPACE_TELEPHONY = "telephony";
field public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
}
@@ -5900,30 +5914,6 @@
method @Nullable public String getString(@NonNull String, @Nullable String);
}
- public static interface DeviceConfig.Rollback {
- field public static final String BOOT_NAMESPACE = "rollback_boot";
- field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
- field public static final String NAMESPACE = "rollback";
- field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
- }
-
- public static interface DeviceConfig.Scheduler {
- field public static final String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
- field public static final String NAMESPACE = "scheduler";
- }
-
- public static interface DeviceConfig.Storage {
- field public static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
- field public static final String NAMESPACE = "storage";
- }
-
- public static interface DeviceConfig.Telephony {
- field public static final String NAMESPACE = "telephony";
- field public static final String RAMPING_RINGER_DURATION = "ramping_ringer_duration";
- field public static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
- field public static final String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
- }
-
public final class DocumentsContract {
method public static boolean isManageMode(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
@@ -6054,6 +6044,7 @@
field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+ field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
}
@@ -6117,6 +6108,8 @@
field public static final String LOCATION_PERMISSIONS_UPGRADE_TO_Q_MODE = "location_permissions_upgrade_to_q_mode";
field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
+ field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
+ field public static final String ODI_CAPTIONS_OPTED_OUT = "odi_captions_opted_out";
field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
@@ -6427,8 +6420,10 @@
method public int getEventType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
+ field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18
field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
+ field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
}
public abstract class ContentCaptureService extends android.app.Service {
@@ -6444,6 +6439,7 @@
method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
+ field public static final String SERVICE_META_DATA = "android.content_capture";
}
public final class SnapshotData implements android.os.Parcelable {
@@ -6644,6 +6640,7 @@
method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+ method public void onCapabilitiesChanged();
method public void onNotificationDirectReplied(@NonNull String);
method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
@@ -7156,9 +7153,10 @@
package android.telephony {
- public static final class AccessNetworkConstants.TransportType {
- field public static final int WLAN = 2; // 0x2
- field public static final int WWAN = 1; // 0x1
+ public final class AccessNetworkConstants {
+ field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff
+ field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2
+ field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1
}
public final class CallAttributes implements android.os.Parcelable {
@@ -7233,7 +7231,6 @@
field public static final int ACCESS_BLOCK_ALL = 2088; // 0x828
field public static final int ACCESS_CLASS_DSAC_REJECTION = 2108; // 0x83c
field public static final int ACCESS_CONTROL_LIST_CHECK_FAILURE = 2128; // 0x850
- field public static final int ACCESS_PROBE_LIMIT_REACHED = 2079; // 0x81f
field public static final int ACTIVATION_REJECTED_BCM_VIOLATION = 48; // 0x30
field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e
field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f
@@ -7348,9 +7345,7 @@
field public static final int INVALID_PRIMARY_NSAPI = 2158; // 0x86e
field public static final int INVALID_SIM_STATE = 2224; // 0x8b0
field public static final int INVALID_TRANSACTION_ID = 81; // 0x51
- field public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 2052; // 0x804
field public static final int IPV6_ADDRESS_TRANSFER_FAILED = 2047; // 0x7ff
- field public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 2053; // 0x805
field public static final int IPV6_PREFIX_UNAVAILABLE = 2250; // 0x8ca
field public static final int IP_ADDRESS_MISMATCH = 119; // 0x77
field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
@@ -7369,6 +7364,10 @@
field public static final int MAC_FAILURE = 2183; // 0x887
field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d
field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876
+ field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f
+ field public static final int MAX_IPV4_CONNECTIONS = 2052; // 0x804
+ field public static final int MAX_IPV6_CONNECTIONS = 2053; // 0x805
+ field public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
field public static final int MESSAGE_INCORRECT_SEMANTIC = 95; // 0x5f
field public static final int MESSAGE_TYPE_UNSUPPORTED = 97; // 0x61
field public static final int MIP_CONFIG_FAILURE = 2050; // 0x802
@@ -7477,7 +7476,6 @@
field public static final int PPP_AUTH_FAILURE = 2229; // 0x8b5
field public static final int PPP_CHAP_FAILURE = 2232; // 0x8b8
field public static final int PPP_CLOSE_IN_PROGRESS = 2233; // 0x8b9
- field public static final int PPP_INACTIVITY_TIMER_EXPIRED = 2046; // 0x7fe
field public static final int PPP_OPTION_MISMATCH = 2230; // 0x8b6
field public static final int PPP_PAP_FAILURE = 2231; // 0x8b7
field public static final int PPP_TIMEOUT = 2228; // 0x8b4
@@ -7678,50 +7676,48 @@
field public static final String MBMS_STREAMING_SERVICE_ACTION = "android.telephony.action.EmbmsStreaming";
}
- public class NetworkRegistrationState implements android.os.Parcelable {
- ctor public NetworkRegistrationState(int, int, int, int, int, boolean, @NonNull int[], @Nullable android.telephony.CellIdentity);
+ public final class NetworkRegistrationInfo implements android.os.Parcelable {
method public int describeContents();
method public int getAccessNetworkTechnology();
- method @NonNull public int[] getAvailableServices();
+ method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
method @Nullable public android.telephony.CellIdentity getCellIdentity();
method @Nullable public android.telephony.DataSpecificRegistrationStates getDataSpecificStates();
method public int getDomain();
- method public int getRegState();
+ method public int getRegistrationState();
method public int getRejectCause();
method public int getRoamingType();
method public int getTransportType();
method public boolean isEmergencyEnabled();
method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationState> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR;
field public static final int DOMAIN_CS = 1; // 0x1
field public static final int DOMAIN_PS = 2; // 0x2
- field public static final int REG_STATE_DENIED = 3; // 0x3
- field public static final int REG_STATE_HOME = 1; // 0x1
- field public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0; // 0x0
- field public static final int REG_STATE_NOT_REG_SEARCHING = 2; // 0x2
- field public static final int REG_STATE_ROAMING = 5; // 0x5
- field public static final int REG_STATE_UNKNOWN = 4; // 0x4
+ field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3
+ field public static final int REGISTRATION_STATE_HOME = 1; // 0x1
+ field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0
+ field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2
+ field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5
+ field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4
field public static final int SERVICE_TYPE_DATA = 2; // 0x2
field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5
field public static final int SERVICE_TYPE_SMS = 3; // 0x3
+ field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0
field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4
field public static final int SERVICE_TYPE_VOICE = 1; // 0x1
}
- public static class NetworkRegistrationState.Builder {
- ctor public NetworkRegistrationState.Builder();
- method @NonNull public android.telephony.NetworkRegistrationState build();
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setAccessNetworkTechnology(int);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setAvailableServices(@NonNull int[]);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setDomain(int);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setEmergencyOnly(boolean);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setNrStatus(int);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setRegState(int);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setRejectCause(int);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setRoamingType(int);
- method @NonNull public android.telephony.NetworkRegistrationState.Builder setTransportType(int);
+ public static final class NetworkRegistrationInfo.Builder {
+ ctor public NetworkRegistrationInfo.Builder();
+ method @NonNull public android.telephony.NetworkRegistrationInfo build();
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAccessNetworkTechnology(int);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setAvailableServices(@NonNull java.util.List<java.lang.Integer>);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setCellIdentity(@Nullable android.telephony.CellIdentity);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setDomain(int);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setEmergencyOnly(boolean);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRegistrationState(int);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setRejectCause(int);
+ method @NonNull public android.telephony.NetworkRegistrationInfo.Builder setTransportType(int);
}
public abstract class NetworkService extends android.app.Service {
@@ -7734,13 +7730,13 @@
public abstract class NetworkService.NetworkServiceProvider implements java.lang.AutoCloseable {
ctor public NetworkService.NetworkServiceProvider(int);
method public abstract void close();
- method public void getNetworkRegistrationState(int, @NonNull android.telephony.NetworkServiceCallback);
+ method public void getNetworkRegistrationInfo(int, @NonNull android.telephony.NetworkServiceCallback);
method public final int getSlotIndex();
- method public final void notifyNetworkRegistrationStateChanged();
+ method public final void notifyNetworkRegistrationInfoChanged();
}
public class NetworkServiceCallback {
- method public void onGetNetworkRegistrationStateComplete(int, @Nullable android.telephony.NetworkRegistrationState);
+ method public void onGetNetworkRegistrationInfoComplete(int, @Nullable android.telephony.NetworkRegistrationInfo);
field public static final int RESULT_ERROR_BUSY = 3; // 0x3
field public static final int RESULT_ERROR_FAILED = 5; // 0x5
field public static final int RESULT_ERROR_ILLEGAL_STATE = 4; // 0x4
@@ -7915,12 +7911,10 @@
}
public class ServiceState implements android.os.Parcelable {
- method @Nullable public android.telephony.NetworkRegistrationState getNetworkRegistrationState(int, int);
- method @NonNull public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates();
- method @Deprecated @NonNull public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStates(int);
- method @Deprecated @Nullable public android.telephony.NetworkRegistrationState getNetworkRegistrationStates(int, int);
- method @NonNull public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForDomain(int);
- method @NonNull public java.util.List<android.telephony.NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(int);
+ method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
+ method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
+ method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
+ method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0
@@ -8030,7 +8024,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getLogicalToPhysicalSlotMapping();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping();
method public static long getMaxNumberVerificationTimeoutMillis();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState();
@@ -8068,7 +8062,7 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataEnabled(int, boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataRoamingEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultisimCarrierRestriction(boolean);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean);
@@ -8356,6 +8350,7 @@
field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
+ field public static final String EXTRA_FROM_SUBSCRIPTION_ID = "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID";
field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
}
@@ -8575,7 +8570,7 @@
field public final java.util.HashMap<java.lang.String,android.os.Bundle> mParticipants;
}
- public class ImsException extends java.lang.Exception {
+ public final class ImsException extends java.lang.Exception {
ctor public ImsException(@Nullable String);
ctor public ImsException(@Nullable String, int);
ctor public ImsException(@Nullable String, int, @Nullable Throwable);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 2c65029..7e04469 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -28,14 +28,6 @@
}
-package android.app.usage {
-
- public final class UsageStatsManager {
- method @Deprecated @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
- }
-
-}
-
package android.content {
public class Intent implements java.lang.Cloneable android.os.Parcelable {
@@ -68,14 +60,6 @@
}
-package android.content.pm {
-
- public static class PackageInstaller.SessionParams implements android.os.Parcelable {
- method @Deprecated public void setEnableRollback();
- }
-
-}
-
package android.location {
public class LocationManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index b7555a2..5e9b405 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -14,6 +14,7 @@
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -133,20 +134,23 @@
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void addHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOps);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void clearHistory();
method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOps(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
- method @RequiresPermission("android.permission.GET_APP_OPS_STATS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
+ method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
method public static int getNumOps();
method public static String[] getOpStrs();
method public boolean isOperationActive(int, int, String);
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
+ method public static int opToDefaultMode(@NonNull String);
method public static String opToPermission(int);
method public static int permissionToOpCode(String);
+ method @RequiresPermission("android.permission.MANAGE_APPOPS") public void reloadNonHistoricalState();
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void resetHistoryParameters();
method @RequiresPermission("android.permission.MANAGE_APPOPS") public void setHistoryParameters(int, long, int);
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(int, int, String, int);
+ method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setMode(String, int, String, int);
method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(String, int, int);
method public void startWatchingActive(@NonNull int[], @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
method public void stopWatchingActive(@NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
- method public static int strOpToOp(String);
+ method public static int strOpToOp(@NonNull String);
field public static final int HISTORICAL_MODE_DISABLED = 0; // 0x0
field public static final int HISTORICAL_MODE_ENABLED_ACTIVE = 1; // 0x1
field public static final int HISTORICAL_MODE_ENABLED_PASSIVE = 2; // 0x2
@@ -168,6 +172,7 @@
field public static final String OPSTR_GET_ACCOUNTS = "android:get_accounts";
field public static final String OPSTR_GPS = "android:gps";
field public static final String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
+ field public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
field public static final String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
field public static final String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
field public static final String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
@@ -415,7 +420,8 @@
public class BackupManager {
method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getConfigurationIntent(String);
method @RequiresPermission("android.permission.BACKUP") public android.content.Intent getDataManagementIntent(String);
- method @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(String);
+ method @Nullable @RequiresPermission("android.permission.BACKUP") public CharSequence getDataManagementIntentLabel(@NonNull String);
+ method @Deprecated @Nullable @RequiresPermission("android.permission.BACKUP") public String getDataManagementLabel(@NonNull String);
method @RequiresPermission("android.permission.BACKUP") public String getDestinationString(String);
}
@@ -655,6 +661,7 @@
method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
+ field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
field public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 128; // 0x80
@@ -720,13 +727,14 @@
}
public final class RollbackManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
+ method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_ROLLBACKS, android.Manifest.permission.TEST_MANAGE_ROLLBACKS}) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
+ method @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS) public void reloadPersistedData();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
field public static final String EXTRA_STATUS_MESSAGE = "android.content.rollback.extra.STATUS_MESSAGE";
+ field public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS = "rollback_lifetime_in_millis";
field public static final int STATUS_FAILURE = 1; // 0x1
field public static final int STATUS_FAILURE_INSTALL = 3; // 0x3
field public static final int STATUS_FAILURE_ROLLBACK_UNAVAILABLE = 2; // 0x2
@@ -1070,6 +1078,14 @@
method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int);
}
+ public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+ ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
+ ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
+ method public int getMaxFrameRate();
+ method public long getMaxMacroBlockRate();
+ method public int getMaxMacroBlocks();
+ }
+
public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable {
method public android.media.MediaPlayer2.DrmInfo getDrmInfo(@NonNull android.media.DataSourceDesc);
method public android.media.MediaDrm.KeyRequest getDrmKeyRequest(@NonNull android.media.DataSourceDesc, @Nullable byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException;
@@ -1174,8 +1190,8 @@
package android.net {
public class CaptivePortal implements android.os.Parcelable {
- ctor public CaptivePortal(android.os.IBinder);
- method public void logEvent(int, String);
+ ctor public CaptivePortal(@NonNull android.os.IBinder);
+ method public void logEvent(int, @NonNull String);
method public void useNetwork();
field public static final int APP_RETURN_DISMISSED = 0; // 0x0
field public static final int APP_RETURN_UNWANTED = 1; // 0x1
@@ -1260,18 +1276,18 @@
public final class StaticIpConfiguration implements android.os.Parcelable {
ctor public StaticIpConfiguration();
- ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
- method public void addDnsServer(java.net.InetAddress);
+ ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ method public void addDnsServer(@NonNull java.net.InetAddress);
method public void clear();
method public int describeContents();
- method public java.util.List<java.net.InetAddress> getDnsServers();
- method public String getDomains();
- method public java.net.InetAddress getGateway();
- method public android.net.LinkAddress getIpAddress();
- method public java.util.List<android.net.RouteInfo> getRoutes(String);
- method public void setDomains(String);
- method public void setGateway(java.net.InetAddress);
- method public void setIpAddress(android.net.LinkAddress);
+ method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+ method @Nullable public String getDomains();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @Nullable public android.net.LinkAddress getIpAddress();
+ method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(String);
+ method public void setDomains(@Nullable String);
+ method public void setGateway(@Nullable java.net.InetAddress);
+ method public void setIpAddress(@Nullable android.net.LinkAddress);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
}
@@ -1305,11 +1321,14 @@
package android.net.apf {
- public class ApfCapabilities {
+ public final class ApfCapabilities implements android.os.Parcelable {
ctor public ApfCapabilities(int, int, int);
+ method public int describeContents();
method public static boolean getApfDrop8023Frames(android.content.Context);
method public static int[] getApfEthTypeBlackList(android.content.Context);
method public boolean hasDataAccess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
field public final int apfPacketFormat;
field public final int apfVersionSupported;
field public final int maximumApfProgramSize;
@@ -1321,28 +1340,28 @@
public final class CaptivePortalProbeResult {
ctor public CaptivePortalProbeResult(int);
- ctor public CaptivePortalProbeResult(int, String, String);
- ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+ ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String);
+ ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String, @Nullable android.net.captiveportal.CaptivePortalProbeSpec);
method public boolean isFailed();
method public boolean isPartialConnectivity();
method public boolean isPortal();
method public boolean isSuccessful();
- field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+ field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
field public static final int FAILED_CODE = 599; // 0x257
field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
field public static final int PORTAL_CODE = 302; // 0x12e
- field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
+ field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
field public static final int SUCCESS_CODE = 204; // 0xcc
- field public final String detectUrl;
+ field @Nullable public final String detectUrl;
field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
- field public final String redirectUrl;
+ field @Nullable public final String redirectUrl;
}
public abstract class CaptivePortalProbeSpec {
- method public String getEncodedSpec();
- method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
- method public java.net.URL getUrl();
- method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String);
+ method @NonNull public String getEncodedSpec();
+ method @NonNull public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
+ method @NonNull public java.net.URL getUrl();
+ method @NonNull public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(@NonNull String);
method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
}
@@ -1353,78 +1372,78 @@
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
}
- public static class ApfProgramEvent.Builder {
+ public static final class ApfProgramEvent.Builder {
ctor public ApfProgramEvent.Builder();
- method public android.net.metrics.ApfProgramEvent build();
- method public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
- method public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
- method public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
- method public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
- method public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
- method public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
+ method @NonNull public android.net.metrics.ApfProgramEvent build();
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long);
+ method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int);
}
public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
}
- public static class ApfStats.Builder {
+ public static final class ApfStats.Builder {
ctor public ApfStats.Builder();
- method public android.net.metrics.ApfStats build();
- method public android.net.metrics.ApfStats.Builder setDroppedRas(int);
- method public android.net.metrics.ApfStats.Builder setDurationMs(long);
- method public android.net.metrics.ApfStats.Builder setMatchingRas(int);
- method public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
- method public android.net.metrics.ApfStats.Builder setParseErrors(int);
- method public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
- method public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
- method public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
- method public android.net.metrics.ApfStats.Builder setReceivedRas(int);
- method public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
+ method @NonNull public android.net.metrics.ApfStats build();
+ method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long);
+ method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int);
+ method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int);
}
public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
}
- public static class DhcpClientEvent.Builder {
+ public static final class DhcpClientEvent.Builder {
ctor public DhcpClientEvent.Builder();
- method public android.net.metrics.DhcpClientEvent build();
- method public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
- method public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
+ method @NonNull public android.net.metrics.DhcpClientEvent build();
+ method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int);
+ method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String);
}
public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event {
ctor public DhcpErrorEvent(int);
method public static int errorCodeWithOption(int, int);
- field public static final int BOOTP_TOO_SHORT;
- field public static final int BUFFER_UNDERFLOW;
- field public static final int DHCP_BAD_MAGIC_COOKIE;
+ field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000
+ field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000
+ field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000
field public static final int DHCP_ERROR = 4; // 0x4
- field public static final int DHCP_INVALID_OPTION_LENGTH;
- field public static final int DHCP_NO_COOKIE;
- field public static final int DHCP_NO_MSG_TYPE;
- field public static final int DHCP_UNKNOWN_MSG_TYPE;
+ field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000
+ field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000
+ field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000
+ field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000
field public static final int L2_ERROR = 1; // 0x1
- field public static final int L2_TOO_SHORT;
- field public static final int L2_WRONG_ETH_TYPE;
+ field public static final int L2_TOO_SHORT = 16842752; // 0x1010000
+ field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000
field public static final int L3_ERROR = 2; // 0x2
- field public static final int L3_INVALID_IP;
- field public static final int L3_NOT_IPV4;
- field public static final int L3_TOO_SHORT;
+ field public static final int L3_INVALID_IP = 33751040; // 0x2030000
+ field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000
+ field public static final int L3_TOO_SHORT = 33619968; // 0x2010000
field public static final int L4_ERROR = 3; // 0x3
- field public static final int L4_NOT_UDP;
- field public static final int L4_WRONG_PORT;
+ field public static final int L4_NOT_UDP = 50397184; // 0x3010000
+ field public static final int L4_WRONG_PORT = 50462720; // 0x3020000
field public static final int MISC_ERROR = 5; // 0x5
- field public static final int PARSING_ERROR;
- field public static final int RECEIVE_ERROR;
+ field public static final int PARSING_ERROR = 84082688; // 0x5030000
+ field public static final int RECEIVE_ERROR = 84017152; // 0x5020000
}
public class IpConnectivityLog {
ctor public IpConnectivityLog();
- method public boolean log(long, android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(String, android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(android.net.Network, int[], android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(int, int[], android.net.metrics.IpConnectivityLog.Event);
- method public boolean log(android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event);
+ method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event);
}
public static interface IpConnectivityLog.Event extends android.os.Parcelable {
@@ -1495,28 +1514,28 @@
field public static final int PROBE_PRIVDNS = 5; // 0x5
}
- public static class ValidationProbeEvent.Builder {
+ public static final class ValidationProbeEvent.Builder {
ctor public ValidationProbeEvent.Builder();
- method public android.net.metrics.ValidationProbeEvent build();
- method public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
- method public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
- method public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
+ method @NonNull public android.net.metrics.ValidationProbeEvent build();
+ method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long);
+ method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean);
+ method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int);
}
}
package android.net.util {
- public class SocketUtils {
+ public final class SocketUtils {
method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
- method public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
- method public static java.net.SocketAddress makePacketSocketAddress(short, int);
- method public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
+ method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
+ method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
@@ -2067,6 +2086,8 @@
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean);
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
+ field public static final String NAMESPACE_ROLLBACK = "rollback";
+ field public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
}
public static interface DeviceConfig.OnPropertiesChangedListener {
@@ -2092,13 +2113,6 @@
method @Nullable public String getString(@NonNull String, @Nullable String);
}
- public static interface DeviceConfig.Rollback {
- field public static final String BOOT_NAMESPACE = "rollback_boot";
- field public static final String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
- field public static final String NAMESPACE = "rollback";
- field public static final String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
- }
-
public final class MediaStore {
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
@@ -2394,8 +2408,10 @@
method public int getEventType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.service.contentcapture.ActivityEvent> CREATOR;
+ field public static final int TYPE_ACTIVITY_DESTROYED = 24; // 0x18
field public static final int TYPE_ACTIVITY_PAUSED = 2; // 0x2
field public static final int TYPE_ACTIVITY_RESUMED = 1; // 0x1
+ field public static final int TYPE_ACTIVITY_STOPPED = 23; // 0x17
}
public abstract class ContentCaptureService extends android.app.Service {
@@ -2411,6 +2427,7 @@
method public void onUserDataRemovalRequest(@NonNull android.view.contentcapture.UserDataRemovalRequest);
method public final void setContentCaptureWhitelist(@Nullable java.util.Set<java.lang.String>, @Nullable java.util.Set<android.content.ComponentName>);
field public static final String SERVICE_INTERFACE = "android.service.contentcapture.ContentCaptureService";
+ field public static final String SERVICE_META_DATA = "android.content_capture";
}
public final class SnapshotData implements android.os.Parcelable {
@@ -2547,7 +2564,8 @@
method public int getCarrierIdListVersion();
method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
- method public void setCarrierTestOverride(String, String, String, String, String, String, String);
+ method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
+ method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
@@ -3168,25 +3186,21 @@
package android.view.inspector {
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public @interface InspectableNodeName {
- method public abstract String value();
- }
-
@java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.FIELD}) public @interface InspectableProperty {
method public abstract int attributeId() default android.content.res.Resources.ID_NULL;
- method public abstract android.view.inspector.InspectableProperty.EnumMap[] enumMapping() default {};
- method public abstract android.view.inspector.InspectableProperty.FlagMap[] flagMapping() default {};
+ method public abstract android.view.inspector.InspectableProperty.EnumEntry[] enumMapping() default {};
+ method public abstract android.view.inspector.InspectableProperty.FlagEntry[] flagMapping() default {};
method public abstract boolean hasAttributeId() default true;
method public abstract String name() default "";
method public abstract android.view.inspector.InspectableProperty.ValueType valueType() default android.view.inspector.InspectableProperty.ValueType.INFERRED;
}
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumMap {
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.EnumEntry {
method public abstract String name();
method public abstract int value();
}
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagMap {
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @java.lang.annotation.Target({java.lang.annotation.ElementType.TYPE}) public static @interface InspectableProperty.FlagEntry {
method public abstract int mask() default 0;
method public abstract String name();
method public abstract int target();
@@ -3215,7 +3229,7 @@
}
public class DatePicker extends android.widget.FrameLayout {
- method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumMap(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode();
+ method @android.view.inspector.InspectableProperty(name="datePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_SPINNER, name="spinner"), @android.view.inspector.InspectableProperty.EnumEntry(value=android.widget.DatePicker.MODE_CALENDAR, name="calendar")}) public int getMode();
field public static final int MODE_CALENDAR = 2; // 0x2
field public static final int MODE_SPINNER = 1; // 0x1
}
@@ -3251,7 +3265,7 @@
method public android.view.View getAmView();
method public android.view.View getHourView();
method public android.view.View getMinuteView();
- method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumMap(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumMap(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode();
+ method @android.view.inspector.InspectableProperty(name="timePickerMode", enumMapping={@android.view.inspector.InspectableProperty.EnumEntry(name="clock", value=android.widget.TimePicker.MODE_CLOCK), @android.view.inspector.InspectableProperty.EnumEntry(name="spinner", value=android.widget.TimePicker.MODE_SPINNER)}) public int getMode();
method public android.view.View getPmView();
field public static final int MODE_CLOCK = 2; // 0x2
field public static final int MODE_SPINNER = 1; // 0x1
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 062ba65..98ab666 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -803,8 +803,8 @@
} else {
String[] names = new String[filter.size()];
filter.toArray(names);
- didRestore = (mRestore.restoreSome(token, observer,
- null, names) == 0);
+ didRestore = (mRestore.restorePackages(token, observer, names,
+ null) == 0);
}
break;
}
diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h
index dcc69b3..718e361 100644
--- a/cmds/idmap2/idmap2/Commands.h
+++ b/cmds/idmap2/idmap2/Commands.h
@@ -20,10 +20,12 @@
#include <string>
#include <vector>
-bool Create(const std::vector<std::string>& args, std::ostream& out_error);
-bool Dump(const std::vector<std::string>& args, std::ostream& out_error);
-bool Lookup(const std::vector<std::string>& args, std::ostream& out_error);
-bool Scan(const std::vector<std::string>& args, std::ostream& out_error);
-bool Verify(const std::vector<std::string>& args, std::ostream& out_error);
+#include "idmap2/Result.h"
+
+android::idmap2::Result<android::idmap2::Unit> Create(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
+android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args);
#endif // IDMAP2_IDMAP2_COMMANDS_H_
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index c416fa1..fdbb210 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -33,14 +33,17 @@
using android::ApkAssets;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
using android::idmap2::Idmap;
using android::idmap2::PoliciesToBitmask;
using android::idmap2::PolicyBitmask;
using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
+using android::idmap2::Unit;
using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::UidHasWriteAccessToPath;
-bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Create(const std::vector<std::string>& args) {
SYSTRACE << "Create " << args;
std::string target_apk_path;
std::string overlay_apk_path;
@@ -63,15 +66,14 @@
&policies)
.OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
&ignore_overlayable);
- if (!opts.Parse(args, out_error)) {
- return false;
+ const auto opts_ok = opts.Parse(args);
+ if (!opts_ok) {
+ return opts_ok.GetError();
}
const uid_t uid = getuid();
if (!UidHasWriteAccessToPath(uid, idmap_path)) {
- out_error << "error: uid " << uid << " does not have write access to " << idmap_path
- << std::endl;
- return false;
+ return Error("uid %d does not have write access to %s", uid, idmap_path.c_str());
}
PolicyBitmask fulfilled_policies = 0;
@@ -79,8 +81,7 @@
if (conv_result) {
fulfilled_policies |= *conv_result;
} else {
- out_error << "error: " << conv_result.GetErrorMessage() << std::endl;
- return false;
+ return conv_result.GetError();
}
if (fulfilled_policies == 0) {
@@ -89,36 +90,33 @@
const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
if (!target_apk) {
- out_error << "error: failed to load apk " << target_apk_path << std::endl;
- return false;
+ return Error("failed to load apk %s", target_apk_path.c_str());
}
const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
if (!overlay_apk) {
- out_error << "error: failed to load apk " << overlay_apk_path << std::endl;
- return false;
+ return Error("failed to load apk %s", overlay_apk_path.c_str());
}
+ std::stringstream stream;
const std::unique_ptr<const Idmap> idmap =
Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- fulfilled_policies, !ignore_overlayable, out_error);
+ fulfilled_policies, !ignore_overlayable, stream);
if (!idmap) {
- return false;
+ return Error("failed to create idmap: %s", stream.str().c_str());
}
umask(kIdmapFilePermissionMask);
std::ofstream fout(idmap_path);
if (fout.fail()) {
- out_error << "failed to open idmap path " << idmap_path << std::endl;
- return false;
+ return Error("failed to open idmap path %s", idmap_path.c_str());
}
BinaryStreamVisitor visitor(fout);
idmap->accept(&visitor);
fout.close();
if (fout.fail()) {
- out_error << "failed to write to idmap path " << idmap_path << std::endl;
- return false;
+ return Error("failed to write to idmap path %s", idmap_path.c_str());
}
- return true;
+ return Unit{};
}
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index 3947703..fd58222 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -17,6 +17,7 @@
#include <fstream>
#include <iostream>
#include <memory>
+#include <sstream>
#include <string>
#include <vector>
@@ -24,14 +25,18 @@
#include "idmap2/Idmap.h"
#include "idmap2/PrettyPrintVisitor.h"
#include "idmap2/RawPrintVisitor.h"
+#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
using android::idmap2::Idmap;
using android::idmap2::PrettyPrintVisitor;
using android::idmap2::RawPrintVisitor;
+using android::idmap2::Result;
+using android::idmap2::Unit;
-bool Dump(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Dump(const std::vector<std::string>& args) {
SYSTRACE << "Dump " << args;
std::string idmap_path;
bool verbose;
@@ -40,14 +45,16 @@
CommandLineOptions("idmap2 dump")
.MandatoryOption("--idmap-path", "input: path to idmap file to pretty-print", &idmap_path)
.OptionalFlag("--verbose", "annotate every byte of the idmap", &verbose);
- if (!opts.Parse(args, out_error)) {
- return false;
+ const auto opts_ok = opts.Parse(args);
+ if (!opts_ok) {
+ return opts_ok.GetError();
}
+ std::stringstream stream;
std::ifstream fin(idmap_path);
- const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, out_error);
+ const std::unique_ptr<const Idmap> idmap = Idmap::FromBinaryStream(fin, stream);
fin.close();
if (!idmap) {
- return false;
+ return Error("failed to load idmap: %s", stream.str().c_str());
}
if (verbose) {
@@ -58,5 +65,5 @@
idmap->accept(&visitor);
}
- return true;
+ return Unit{};
}
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 83a40ef..677c6fa 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -57,6 +57,7 @@
using android::idmap2::IdmapHeader;
using android::idmap2::ResourceId;
using android::idmap2::Result;
+using android::idmap2::Unit;
using android::idmap2::Xml;
using android::idmap2::ZipFile;
using android::util::Utf16ToUtf8;
@@ -157,7 +158,7 @@
}
} // namespace
-bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Lookup(const std::vector<std::string>& args) {
SYSTRACE << "Lookup " << args;
std::vector<std::string> idmap_paths;
std::string config_str;
@@ -172,14 +173,14 @@
"'[package:]type/name') to look up",
&resid_str);
- if (!opts.Parse(args, out_error)) {
- return false;
+ const auto opts_ok = opts.Parse(args);
+ if (!opts_ok) {
+ return opts_ok.GetError();
}
ConfigDescription config;
if (!ConfigDescription::Parse(config_str, &config)) {
- out_error << "error: failed to parse config" << std::endl;
- return false;
+ return Error("failed to parse config");
}
std::vector<std::unique_ptr<const ApkAssets>> apk_assets;
@@ -191,39 +192,33 @@
auto idmap_header = IdmapHeader::FromBinaryStream(fin);
fin.close();
if (!idmap_header) {
- out_error << "error: failed to read idmap from " << idmap_path << std::endl;
- return false;
+ return Error("failed to read idmap from %s", idmap_path.c_str());
}
if (i == 0) {
target_path = idmap_header->GetTargetPath().to_string();
auto target_apk = ApkAssets::Load(target_path);
if (!target_apk) {
- out_error << "error: failed to read target apk from " << target_path << std::endl;
- return false;
+ return Error("failed to read target apk from %s", target_path.c_str());
}
apk_assets.push_back(std::move(target_apk));
const Result<std::string> package_name =
GetTargetPackageNameFromManifest(idmap_header->GetOverlayPath().to_string());
if (!package_name) {
- out_error << "error: failed to parse android:targetPackage from overlay manifest"
- << std::endl;
- return false;
+ return Error("failed to parse android:targetPackage from overlay manifest");
}
target_package_name = *package_name;
} else if (target_path != idmap_header->GetTargetPath()) {
- out_error << "error: different target APKs (expected target APK " << target_path << " but "
- << idmap_path << " has target APK " << idmap_header->GetTargetPath() << ")"
- << std::endl;
- return false;
+ return Error("different target APKs (expected target APK %s but %s has target APK %s)",
+ target_path.c_str(), idmap_path.c_str(),
+ idmap_header->GetTargetPath().to_string().c_str());
}
auto overlay_apk = ApkAssets::LoadOverlay(idmap_path);
if (!overlay_apk) {
- out_error << "error: failed to read overlay apk from " << idmap_header->GetOverlayPath()
- << std::endl;
- return false;
+ return Error("failed to read overlay apk from %s",
+ idmap_header->GetOverlayPath().to_string().c_str());
}
apk_assets.push_back(std::move(overlay_apk));
}
@@ -238,16 +233,14 @@
const Result<ResourceId> resid = ParseResReference(am, resid_str, target_package_name);
if (!resid) {
- out_error << "error: failed to parse resource ID" << std::endl;
- return false;
+ return Error(resid.GetError(), "failed to parse resource ID");
}
const Result<std::string> value = GetValue(am, *resid);
if (!value) {
- out_error << StringPrintf("error: resource 0x%08x not found", *resid) << std::endl;
- return false;
+ return Error(value.GetError(), "resource 0x%08x not found", *resid);
}
std::cout << *value << std::endl;
- return true;
+ return Unit{};
}
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index a0ffccb..d8867fe 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -24,14 +24,17 @@
#include <vector>
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include "Commands.h"
using android::idmap2::CommandLineOptions;
+using android::idmap2::Result;
+using android::idmap2::Unit;
using NameToFunctionMap =
- std::map<std::string, std::function<bool(const std::vector<std::string>&, std::ostream&)>>;
+ std::map<std::string, std::function<Result<Unit>(const std::vector<std::string>&)>>;
namespace {
@@ -69,5 +72,10 @@
PrintUsage(commands, std::cerr);
return EXIT_FAILURE;
}
- return iter->second(*args, std::cerr) ? EXIT_SUCCESS : EXIT_FAILURE;
+ const auto result = iter->second(*args);
+ if (!result) {
+ std::cerr << "error: " << result.GetErrorMessage() << std::endl;
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
}
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index e85f132..24331af 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -30,6 +30,7 @@
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/ResourceUtils.h"
+#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include "idmap2/Xml.h"
#include "idmap2/ZipFile.h"
@@ -37,6 +38,7 @@
#include "Commands.h"
using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
using android::idmap2::Idmap;
using android::idmap2::kPolicyProduct;
using android::idmap2::kPolicyPublic;
@@ -45,6 +47,7 @@
using android::idmap2::PolicyBitmask;
using android::idmap2::PolicyFlags;
using android::idmap2::Result;
+using android::idmap2::Unit;
using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::idmap2::utils::FindFiles;
using android::idmap2::utils::OverlayManifestInfo;
@@ -69,8 +72,8 @@
return version == "Q" || version == "q";
}
-std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
- bool recursive, std::ostream& out_error) {
+Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs,
+ bool recursive) {
SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
const auto predicate = [](unsigned char type, const std::string& path) -> bool {
static constexpr size_t kExtLen = 4; // strlen(".apk")
@@ -82,8 +85,7 @@
for (const auto& dir : dirs) {
const auto apk_paths = FindFiles(dir, recursive, predicate);
if (!apk_paths) {
- out_error << "error: failed to open directory " << dir << std::endl;
- return nullptr;
+ return Error("failed to open directory %s", dir.c_str());
}
paths.insert(apk_paths->cbegin(), apk_paths->cend());
}
@@ -110,7 +112,7 @@
} // namespace
-bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Scan(const std::vector<std::string>& args) {
SYSTRACE << "Scan " << args;
std::vector<std::string> input_directories;
std::string target_package_name;
@@ -135,22 +137,22 @@
"input: an overlayable policy this overlay fulfills "
"(if none or supplied, the overlays will not have their policies overriden",
&override_policies);
- if (!opts.Parse(args, out_error)) {
- return false;
+ const auto opts_ok = opts.Parse(args);
+ if (!opts_ok) {
+ return opts_ok.GetError();
}
- const auto apk_paths = FindApkFiles(input_directories, recursive, out_error);
+ const auto apk_paths = FindApkFiles(input_directories, recursive);
if (!apk_paths) {
- return false;
+ return Error(apk_paths.GetError(), "failed to find apk files");
}
std::vector<InputOverlay> interesting_apks;
- for (const std::string& path : *apk_paths) {
+ for (const std::string& path : **apk_paths) {
Result<OverlayManifestInfo> overlay_info =
ExtractOverlayManifestInfo(path, /* assert_overlay */ false);
if (!overlay_info) {
- out_error << "error: " << overlay_info.GetErrorMessage() << std::endl;
- return false;
+ return overlay_info.GetError();
}
if (!overlay_info->is_static) {
@@ -194,16 +196,13 @@
std::stringstream stream;
for (const auto& overlay : interesting_apks) {
- // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
- std::stringstream dev_null;
-
std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
for (const std::string& policy : overlay.policies) {
verify_args.emplace_back("--policy");
verify_args.emplace_back(policy);
}
- if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+ if (!Verify(std::vector<std::string>(verify_args))) {
std::vector<std::string> create_args = {"--target-apk-path", target_apk_path,
"--overlay-apk-path", overlay.apk_path,
"--idmap-path", overlay.idmap_path};
@@ -216,8 +215,9 @@
create_args.emplace_back(policy);
}
- if (!Create(create_args, out_error)) {
- return false;
+ const auto create_ok = Create(create_args);
+ if (!create_ok) {
+ return Error(create_ok.GetError(), "failed to create idmap");
}
}
@@ -226,5 +226,5 @@
std::cout << stream.str();
- return true;
+ return Unit{};
}
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp
index d8fe7aa..9cb67b3 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/Verify.cpp
@@ -21,29 +21,39 @@
#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
using android::idmap2::CommandLineOptions;
+using android::idmap2::Error;
using android::idmap2::IdmapHeader;
+using android::idmap2::Result;
+using android::idmap2::Unit;
-bool Verify(const std::vector<std::string>& args, std::ostream& out_error) {
+Result<Unit> Verify(const std::vector<std::string>& args) {
SYSTRACE << "Verify " << args;
std::string idmap_path;
const CommandLineOptions opts =
CommandLineOptions("idmap2 verify")
.MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path);
- if (!opts.Parse(args, out_error)) {
- return false;
+
+ const auto opts_ok = opts.Parse(args);
+ if (!opts_ok) {
+ return opts_ok.GetError();
}
std::ifstream fin(idmap_path);
const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
fin.close();
if (!header) {
- out_error << "error: failed to parse idmap header" << std::endl;
- return false;
+ return Error("failed to parse idmap header");
}
- return header->IsUpToDate(out_error);
+ const auto header_ok = header->IsUpToDate();
+ if (!header_ok) {
+ return Error(header_ok.GetError(), "idmap not up to date");
+ }
+
+ return Unit{};
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index fa94414..e03a9cc 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -104,8 +104,7 @@
std::ifstream fin(idmap_path);
const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
fin.close();
- std::stringstream dev_null;
- *_aidl_return = header && header->IsUpToDate(dev_null);
+ *_aidl_return = header && header->IsUpToDate();
// TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index 6db6bf9..52ac818 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -23,6 +23,8 @@
#include <string>
#include <vector>
+#include "idmap2/Result.h"
+
namespace android::idmap2 {
/*
@@ -46,7 +48,7 @@
std::string* value);
CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
std::vector<std::string>* value);
- bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
+ Result<Unit> Parse(const std::vector<std::string>& argv) const;
void Usage(std::ostream& out) const;
private:
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 1666dc8..673d18d 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -115,7 +115,7 @@
// Invariant: anytime the idmap data encoding is changed, the idmap version
// field *must* be incremented. Because of this, we know that if the idmap
// header is up-to-date the entire file is up-to-date.
- bool IsUpToDate(std::ostream& out_error) const;
+ Result<Unit> IsUpToDate() const;
void accept(Visitor* v) const;
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index a49a607..d5fd2ce 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -19,12 +19,14 @@
#include <iostream>
#include <memory>
#include <set>
+#include <sstream>
#include <string>
#include <vector>
#include "android-base/macros.h"
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/Result.h"
namespace android::idmap2 {
@@ -77,7 +79,7 @@
return *this;
}
-bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
+Result<Unit> CommandLineOptions::Parse(const std::vector<std::string>& argv) const {
const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
});
@@ -89,8 +91,9 @@
for (size_t i = 0; i < argv_size; i++) {
const std::string arg = argv[i];
if ("--help" == arg || "-h" == arg) {
- Usage(outError);
- return false;
+ std::stringstream stream;
+ Usage(stream);
+ return Error("%s", stream.str().c_str());
}
bool match = false;
for (const Option& opt : options_) {
@@ -100,9 +103,9 @@
if (opt.argument) {
i++;
if (i >= argv_size) {
- outError << "error: " << opt.name << ": missing argument" << std::endl;
- Usage(outError);
- return false;
+ std::stringstream stream;
+ Usage(stream);
+ return Error("%s: missing argument\n%s", opt.name.c_str(), stream.str().c_str());
}
}
opt.action(argv[i]);
@@ -111,20 +114,27 @@
}
}
if (!match) {
- outError << "error: " << arg << ": unknown option" << std::endl;
- Usage(outError);
- return false;
+ std::stringstream stream;
+ Usage(stream);
+ return Error("%s: unknown option\n%s", arg.c_str(), stream.str().c_str());
}
}
if (!mandatory_opts.empty()) {
+ std::stringstream stream;
+ bool separator = false;
for (const auto& opt : mandatory_opts) {
- outError << "error: " << opt << ": missing mandatory option" << std::endl;
+ if (separator) {
+ stream << ", ";
+ }
+ separator = true;
+ stream << opt << ": missing mandatory option";
}
- Usage(outError);
- return false;
+ stream << std::endl;
+ Usage(stream);
+ return Error("%s", stream.str().c_str());
}
- return true;
+ return Unit{};
}
void CommandLineOptions::Usage(std::ostream& out) const {
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index a7d180c..e8e19d8 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -56,7 +56,7 @@
}
inline const std::map<TypeId, std::set<std::pair<ResourceId, ResourceId>>>& WARN_UNUSED
- Map() const {
+ Map() const {
return map_;
}
@@ -142,62 +142,46 @@
return std::move(idmap_header);
}
-bool IdmapHeader::IsUpToDate(std::ostream& out_error) const {
+Result<Unit> IdmapHeader::IsUpToDate() const {
if (magic_ != kIdmapMagic) {
- out_error << base::StringPrintf("error: bad magic: actual 0x%08x, expected 0x%08x", magic_,
- kIdmapMagic)
- << std::endl;
- return false;
+ return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
}
if (version_ != kIdmapCurrentVersion) {
- out_error << base::StringPrintf("error: bad version: actual 0x%08x, expected 0x%08x", version_,
- kIdmapCurrentVersion)
- << std::endl;
- return false;
+ return Error("bad version: actual 0x%08x, expected 0x%08x", version_, kIdmapCurrentVersion);
}
const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_);
if (!target_zip) {
- out_error << "error: failed to open target " << target_path_ << std::endl;
- return false;
+ return Error("failed to open target %s", GetTargetPath().to_string().c_str());
}
Result<uint32_t> target_crc = GetCrc(*target_zip);
if (!target_crc) {
- out_error << "error: failed to get target crc" << std::endl;
- return false;
+ return Error("failed to get target crc");
}
if (target_crc_ != *target_crc) {
- out_error << base::StringPrintf(
- "error: bad target crc: idmap version 0x%08x, file system version 0x%08x",
- target_crc_, *target_crc)
- << std::endl;
- return false;
+ return Error("bad target crc: idmap version 0x%08x, file system version 0x%08x", target_crc_,
+ *target_crc);
}
const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_);
if (!overlay_zip) {
- out_error << "error: failed to open overlay " << overlay_path_ << std::endl;
- return false;
+ return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str());
}
Result<uint32_t> overlay_crc = GetCrc(*overlay_zip);
if (!overlay_crc) {
- out_error << "error: failed to get overlay crc" << std::endl;
- return false;
+ return Error("failed to get overlay crc");
}
if (overlay_crc_ != *overlay_crc) {
- out_error << base::StringPrintf(
- "error: bad overlay crc: idmap version 0x%08x, file system version 0x%08x",
- overlay_crc_, *overlay_crc)
- << std::endl;
- return false;
+ return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
+ *overlay_crc);
}
- return true;
+ return Unit{};
}
std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std::istream& stream) {
@@ -452,7 +436,7 @@
continue;
}
- if (!enforce_overlayable) {
+ if (enforce_overlayable) {
Result<Unit> success =
CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid);
if (!success) {
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index 39f18d3..d567af6 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -46,14 +46,13 @@
CommandLineOptions opts =
CommandLineOptions("test").OptionalFlag("--foo", "", &foo).OptionalFlag("--bar", "", &bar);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--foo", "--bar"}, fakeStdErr);
+ auto success = opts.Parse({"--foo", "--bar"});
ASSERT_TRUE(success);
ASSERT_TRUE(foo);
ASSERT_TRUE(bar);
foo = bar = false;
- success = opts.Parse({"--foo"}, fakeStdErr);
+ success = opts.Parse({"--foo"});
ASSERT_TRUE(success);
ASSERT_TRUE(foo);
ASSERT_FALSE(bar);
@@ -65,21 +64,19 @@
CommandLineOptions opts = CommandLineOptions("test")
.MandatoryOption("--foo", "", &foo)
.MandatoryOption("--bar", "", &bar);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+ auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
ASSERT_TRUE(success);
ASSERT_EQ(foo, "FOO");
ASSERT_EQ(bar, "BAR");
- success = opts.Parse({"--foo"}, fakeStdErr);
+ success = opts.Parse({"--foo"});
ASSERT_FALSE(success);
}
TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsButExpectedOnce) {
std::string foo;
CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &foo);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"}, fakeStdErr);
+ auto success = opts.Parse({"--foo", "FIRST", "--foo", "SECOND"});
ASSERT_TRUE(success);
ASSERT_EQ(foo, "SECOND");
}
@@ -87,8 +84,7 @@
TEST(CommandLineOptionsTests, MandatoryOptionMultipleArgsAndExpectedOnceOrMore) {
std::vector<std::string> args;
CommandLineOptions opts = CommandLineOptions("test").MandatoryOption("--foo", "", &args);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--foo", "FOO", "--foo", "BAR"}, fakeStdErr);
+ auto success = opts.Parse({"--foo", "FOO", "--foo", "BAR"});
ASSERT_TRUE(success);
ASSERT_EQ(args.size(), 2U);
ASSERT_EQ(args[0], "FOO");
@@ -101,23 +97,22 @@
CommandLineOptions opts = CommandLineOptions("test")
.OptionalOption("--foo", "", &foo)
.OptionalOption("--bar", "", &bar);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+ auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
ASSERT_TRUE(success);
ASSERT_EQ(foo, "FOO");
ASSERT_EQ(bar, "BAR");
- success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+ success = opts.Parse({"--foo", "BAZ"});
ASSERT_TRUE(success);
ASSERT_EQ(foo, "BAZ");
- success = opts.Parse({"--foo"}, fakeStdErr);
+ success = opts.Parse({"--foo"});
ASSERT_FALSE(success);
- success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+ success = opts.Parse({"--foo", "--bar", "BAR"});
ASSERT_FALSE(success);
- success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+ success = opts.Parse({"--foo", "FOO", "--bar"});
ASSERT_FALSE(success);
}
@@ -127,8 +122,7 @@
CommandLineOptions opts = CommandLineOptions("test")
.OptionalOption("--foo", "", &foo)
.OptionalOption("--bar", "", &bar);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+ auto success = opts.Parse({"--foo", "FOO", "--bar", "BAR"});
ASSERT_TRUE(success);
ASSERT_EQ(foo.size(), 1U);
ASSERT_EQ(foo[0], "FOO");
@@ -137,7 +131,7 @@
foo.clear();
bar.clear();
- success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+ success = opts.Parse({"--foo", "BAZ"});
ASSERT_TRUE(success);
ASSERT_EQ(foo.size(), 1U);
ASSERT_EQ(foo[0], "BAZ");
@@ -145,8 +139,7 @@
foo.clear();
bar.clear();
- success =
- opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+ success = opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"});
ASSERT_TRUE(success);
ASSERT_EQ(foo.size(), 2U);
ASSERT_EQ(foo[0], "BAZ");
@@ -157,17 +150,17 @@
foo.clear();
bar.clear();
- success = opts.Parse({"--foo"}, fakeStdErr);
+ success = opts.Parse({"--foo"});
ASSERT_FALSE(success);
foo.clear();
bar.clear();
- success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+ success = opts.Parse({"--foo", "--bar", "BAR"});
ASSERT_FALSE(success);
foo.clear();
bar.clear();
- success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+ success = opts.Parse({"--foo", "FOO", "--bar"});
ASSERT_FALSE(success);
}
@@ -179,14 +172,13 @@
.MandatoryOption("--foo", "", &foo)
.OptionalFlag("--baz", "", &baz)
.OptionalOption("--bar", "", &bar);
- std::ostream fakeStdErr(nullptr);
- bool success = opts.Parse({"--unexpected"}, fakeStdErr);
+ auto success = opts.Parse({"--unexpected"});
ASSERT_FALSE(success);
- success = opts.Parse({"--bar", "BAR"}, fakeStdErr);
+ success = opts.Parse({"--bar", "BAR"});
ASSERT_FALSE(success);
- success = opts.Parse({"--baz", "--foo", "FOO"}, fakeStdErr);
+ success = opts.Parse({"--baz", "--foo", "FOO"});
ASSERT_TRUE(success);
ASSERT_TRUE(baz);
ASSERT_EQ(foo, "FOO");
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 8d65428..c20ae7b 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -501,7 +501,7 @@
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
- ASSERT_TRUE(header->IsUpToDate(error)) << error.str();
+ ASSERT_TRUE(header->IsUpToDate());
// magic: bytes (0x0, 0x03)
std::string bad_magic_string(stream.str());
@@ -514,7 +514,7 @@
IdmapHeader::FromBinaryStream(bad_magic_stream);
ASSERT_THAT(bad_magic_header, NotNull());
ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic());
- ASSERT_FALSE(bad_magic_header->IsUpToDate(error));
+ ASSERT_FALSE(bad_magic_header->IsUpToDate());
// version: bytes (0x4, 0x07)
std::string bad_version_string(stream.str());
@@ -527,7 +527,7 @@
IdmapHeader::FromBinaryStream(bad_version_stream);
ASSERT_THAT(bad_version_header, NotNull());
ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion());
- ASSERT_FALSE(bad_version_header->IsUpToDate(error));
+ ASSERT_FALSE(bad_version_header->IsUpToDate());
// target crc: bytes (0x8, 0xb)
std::string bad_target_crc_string(stream.str());
@@ -540,7 +540,7 @@
IdmapHeader::FromBinaryStream(bad_target_crc_stream);
ASSERT_THAT(bad_target_crc_header, NotNull());
ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
- ASSERT_FALSE(bad_target_crc_header->IsUpToDate(error));
+ ASSERT_FALSE(bad_target_crc_header->IsUpToDate());
// overlay crc: bytes (0xc, 0xf)
std::string bad_overlay_crc_string(stream.str());
@@ -553,7 +553,7 @@
IdmapHeader::FromBinaryStream(bad_overlay_crc_stream);
ASSERT_THAT(bad_overlay_crc_header, NotNull());
ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
- ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate(error));
+ ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate());
// target path: bytes (0x10, 0x10f)
std::string bad_target_path_string(stream.str());
@@ -563,7 +563,7 @@
IdmapHeader::FromBinaryStream(bad_target_path_stream);
ASSERT_THAT(bad_target_path_header, NotNull());
ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
- ASSERT_FALSE(bad_target_path_header->IsUpToDate(error));
+ ASSERT_FALSE(bad_target_path_header->IsUpToDate());
// overlay path: bytes (0x110, 0x20f)
std::string bad_overlay_path_string(stream.str());
@@ -573,7 +573,7 @@
IdmapHeader::FromBinaryStream(bad_overlay_path_stream);
ASSERT_THAT(bad_overlay_path_header, NotNull());
ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath());
- ASSERT_FALSE(bad_overlay_path_header->IsUpToDate(error));
+ ASSERT_FALSE(bad_overlay_path_header->IsUpToDate());
}
class TestVisitor : public Visitor {
diff --git a/cmds/idmap2/tests/data/overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
index a7767a6..619bb6c 100644
--- a/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/overlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="test.overlay">
+ <application android:hasCode="false"/>
<overlay
android:targetPackage="test.target"
android:targetName="TestResources"/>
diff --git a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
index 5dacebd..9e6a453 100644
--- a/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/signature-overlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="test.overlay.system">
+ <application android:hasCode="false"/>
<overlay
android:targetPackage="test.target"
android:targetName="TestResources"/>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
index ae687d3..c7b652c 100644
--- a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="test.overlay.system.invalid">
+ <application android:hasCode="false"/>
<overlay
android:targetPackage="test.target"
android:targetName="TestResources"/>
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
index 5dacebd..9e6a453 100644
--- a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="test.overlay.system">
+ <application android:hasCode="false"/>
<overlay
android:targetPackage="test.target"
android:targetName="TestResources"/>
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 1526d66..f78ae38 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1198,30 +1198,48 @@
}
// TODO: add verifier permission
- userid_t userId = multiuser_get_user_id(uid);
+ bool readTrainInfoSuccess = false;
+ InstallTrainInfo trainInfo;
+ if (trainVersionCode == -1 || experimentIds.empty() || trainName.size() == 0) {
+ readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo);
+ }
- bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
- bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
- bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
-
- ProtoOutputStream proto;
- for (const auto& expId : experimentIds) {
- proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
- (long long)expId);
+ if (trainVersionCode == -1 && readTrainInfoSuccess) {
+ trainVersionCode = trainInfo.trainVersionCode;
}
vector<uint8_t> experimentIdsProtoBuffer;
- experimentIdsProtoBuffer.resize(proto.size());
- size_t pos = 0;
- auto iter = proto.data();
- while (iter.readBuffer() != NULL) {
- size_t toRead = iter.currentToRead();
- std::memcpy(&(experimentIdsProtoBuffer[pos]), iter.readBuffer(), toRead);
- pos += toRead;
- iter.rp()->move(toRead);
+ if (readTrainInfoSuccess && experimentIds.empty()) {
+ experimentIdsProtoBuffer = trainInfo.experimentIds;
+ } else {
+ ProtoOutputStream proto;
+ for (const auto& expId : experimentIds) {
+ proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
+ (long long)expId);
+ }
+
+ experimentIdsProtoBuffer.resize(proto.size());
+ size_t pos = 0;
+ auto iter = proto.data();
+ while (iter.readBuffer() != NULL) {
+ size_t toRead = iter.currentToRead();
+ std::memcpy(&(experimentIdsProtoBuffer[pos]), iter.readBuffer(), toRead);
+ pos += toRead;
+ iter.rp()->move(toRead);
+ }
}
- std::string trainNameUtf8 = std::string(String8(trainName).string());
+ std::string trainNameUtf8;
+ if (readTrainInfoSuccess && trainName.size() == 0) {
+ trainNameUtf8 = trainInfo.trainName;
+ } else {
+ trainNameUtf8 = std::string(String8(trainName).string());
+ }
+
+ userid_t userId = multiuser_get_user_id(uid);
+ bool requiresStaging = options & IStatsManager::FLAG_REQUIRE_STAGING;
+ bool rollbackEnabled = options & IStatsManager::FLAG_ROLLBACK_ENABLED;
+ bool requiresLowLatencyMonitor = options & IStatsManager::FLAG_REQUIRE_LOW_LATENCY_MONITOR;
LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled,
requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId);
mProcessor->OnLogEvent(&event);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 3246d19..d331c0f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -45,6 +45,7 @@
import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
+import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto";
import "frameworks/base/core/proto/android/stats/style/style_enums.proto";
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
@@ -250,6 +251,7 @@
HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
StyleUIChanged style_ui_changed = 179;
PrivacyIndicatorsInteracted privacy_indicators_interacted = 180;
+ AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
}
// Pulled events will start at field 10000.
@@ -308,7 +310,7 @@
DangerousPermissionState dangerous_permission_state = 10050;
TrainInfo train_info = 10051;
TimeZoneDataInfo time_zone_data_info = 10052;
- SDCardInfo sdcard_info = 10053;
+ ExternalStorageInfo external_storage_info = 10053;
GpuStatsGlobalInfo gpu_stats_global_info = 10054;
GpuStatsAppInfo gpu_stats_app_info = 10055;
SystemIonHeapSize system_ion_heap_size = 10056;
@@ -2063,6 +2065,9 @@
// HCI reason code associated with this event
// Default: STATUS_UNKNOWN
optional android.bluetooth.hci.StatusEnum reason_code = 6;
+ // A status value related to this specific event
+ // Default: 0
+ optional int64 event_value = 7;
}
/**
@@ -2558,6 +2563,18 @@
}
/**
+ * Logs whenever an app is installed on external storage.
+ * Logged from:
+ frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+ */
+message AppInstallOnExternalStorageReported {
+ // The type of external storage.
+ optional android.stats.storage.ExternalStorageType storage_type = 1;
+ // The name of the package that is installed on the sd card.
+ optional string package_name = 2;
+}
+
+/**
* Logs when an app crashes.
* Logged from:
* frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3297,25 +3314,27 @@
}
/**
- * Logs that an SD card is mounted and information about it, its type (public or private) and the
- * size in bytes.
+ * Logs that external storage is mounted and information about it, the storage type (sd card/usb/
+ * others), its type (public or private) and the size in bytes.
* Pulled from:
* StatsCompanionService
*/
-message SDCardInfo {
+message ExternalStorageInfo {
- enum Type {
+ enum VolumeType {
UNKNOWN = 0;
- TYPE_PUBLIC = 1;
- TYPE_PRIVATE = 2;
- OTHERS = 3;
+ PUBLIC = 1;
+ PRIVATE = 2;
+ OTHER = 3;
}
- // Type of the SD card: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
- optional Type type = 1;
+ // The type of external storage.
+ optional android.stats.storage.ExternalStorageType storage_type = 1;
+ // Type of the volume: TYPE_PUBLIC if portable and TYPE_PRIVATE if internal.
+ optional VolumeType volume_type = 2;
// Total size of the sd card in bytes.
- optional int64 size_bytes = 2;
+ optional int64 size_bytes = 3;
}
/*
@@ -4913,7 +4932,7 @@
// since boot, not including sleep (see SystemClock.uptimeMillis()).
optional int64 last_compact_timestamp_ms_since_boot = 14;
- // The oom_score_adj at the time of compaction.
+ // The "setAdj" (i.e. previous) oom_score_adj at the time of compaction.
optional int32 oom_score_adj = 15;
// The process state at the time of compaction.
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index c7ae656..2abfc24 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -242,9 +242,9 @@
// TimeZoneDataInfo.
{android::util::TIME_ZONE_DATA_INFO,
{.puller = new StatsCompanionServicePuller(android::util::TIME_ZONE_DATA_INFO)}},
- // SDCardInfo
- {android::util::SDCARD_INFO,
- {.puller = new StatsCompanionServicePuller(android::util::SDCARD_INFO)}},
+ // ExternalStorageInfo
+ {android::util::EXTERNAL_STORAGE_INFO,
+ {.puller = new StatsCompanionServicePuller(android::util::EXTERNAL_STORAGE_INFO)}},
// GpuStatsGlobalInfo
{android::util::GPU_STATS_GLOBAL_INFO,
{.puller = new GpuStatsPuller(android::util::GPU_STATS_GLOBAL_INFO)}},
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 254d7d5..c023e6f 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -319,10 +319,11 @@
return;
}
- flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
// Setup the bucket start time and number.
int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
- mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
+
mCurrentBucketNum += numBucketsForward;
VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
@@ -375,6 +376,7 @@
// Only resets the counters, but doesn't setup the times nor numbers.
// (Do not clear since the old one is still referenced in mAnomalyTrackers).
mCurrentSlicedCounter = std::make_shared<DimToValMap>();
+ mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
}
// Rough estimate of CountMetricProducer buffer stored. This number will be
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 7dc4e2d..615c7f2 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -559,26 +559,10 @@
return;
}
VLOG("flushing...........");
- for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
- whatIt != mCurrentSlicedDurationTrackerMap.end();) {
- for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
- if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) {
- VLOG("erase bucket for key %s %s",
- whatIt->first.toString().c_str(), it->first.toString().c_str());
- it = whatIt->second.erase(it);
- } else {
- ++it;
- }
- }
- if (whatIt->second.empty()) {
- whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt);
- } else {
- whatIt++;
- }
- }
-
int numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
- mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
+
mCurrentBucketNum += numBucketsForward;
}
@@ -602,6 +586,7 @@
}
}
StatsdStats::getInstance().noteBucketCount(mMetricId);
+ mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
}
void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 2b6cac8..2f9afa5 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -529,11 +529,11 @@
return;
}
- flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
-
// Adjusts the bucket start and end times.
int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
- mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ int64_t nextBucketNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+ flushCurrentBucketLocked(eventTimeNs, nextBucketNs);
+
mCurrentBucketNum += numBucketsForward;
VLOG("Gauge metric %lld: new bucket start time: %lld", (long long)mMetricId,
(long long)mCurrentBucketStartTimeNs);
@@ -578,6 +578,7 @@
StatsdStats::getInstance().noteBucketCount(mMetricId);
mCurrentSlicedBucket = std::make_shared<DimToGaugeAtomsMap>();
+ mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
}
size_t GaugeMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 27ee570..18bfdfc 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -787,7 +787,6 @@
}
int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs);
- mCurrentBucketNum += numBucketsForward;
if (numBucketsForward > 1) {
VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
@@ -816,10 +815,9 @@
mSkippedBuckets.emplace_back(mCurrentBucketStartTimeNs, bucketEndTime);
}
- if (!mCurrentBucketIsInvalid) {
- appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
- }
+ appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
initCurrentSlicedBucket(nextBucketStartTimeNs);
+ mCurrentBucketNum += numBucketsForward;
}
ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
@@ -879,7 +877,17 @@
}
void ValueMetricProducer::appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs) {
- if (eventTimeNs > fullBucketEndTimeNs) { // If full bucket, send to anomaly tracker.
+ bool isFullBucketReached = eventTimeNs > fullBucketEndTimeNs;
+ if (mCurrentBucketIsInvalid) {
+ if (isFullBucketReached) {
+ // If the bucket is invalid, we ignore the full bucket since it contains invalid data.
+ mCurrentFullBucket.clear();
+ }
+ // Current bucket is invalid, we do not add it to the full bucket.
+ return;
+ }
+
+ if (isFullBucketReached) { // If full bucket, send to anomaly tracker.
// Accumulate partial buckets with current value and then send to anomaly tracker.
if (mCurrentFullBucket.size() > 0) {
for (const auto& slice : mCurrentSlicedBucket) {
@@ -887,7 +895,10 @@
continue;
}
// TODO: fix this when anomaly can accept double values
- mCurrentFullBucket[slice.first] += slice.second[0].value.long_value;
+ auto& interval = slice.second[0];
+ if (interval.hasValue) {
+ mCurrentFullBucket[slice.first] += interval.value.long_value;
+ }
}
for (const auto& slice : mCurrentFullBucket) {
for (auto& tracker : mAnomalyTrackers) {
@@ -903,8 +914,11 @@
for (auto& tracker : mAnomalyTrackers) {
if (tracker != nullptr) {
// TODO: fix this when anomaly can accept double values
- tracker->addPastBucket(slice.first, slice.second[0].value.long_value,
- mCurrentBucketNum);
+ auto& interval = slice.second[0];
+ if (interval.hasValue) {
+ tracker->addPastBucket(slice.first, interval.value.long_value,
+ mCurrentBucketNum);
+ }
}
}
}
@@ -913,7 +927,10 @@
// Accumulate partial bucket.
for (const auto& slice : mCurrentSlicedBucket) {
// TODO: fix this when anomaly can accept double values
- mCurrentFullBucket[slice.first] += slice.second[0].value.long_value;
+ auto& interval = slice.second[0];
+ if (interval.hasValue) {
+ mCurrentFullBucket[slice.first] += interval.value.long_value;
+ }
}
}
}
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index f317c37..12cec5d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -178,7 +178,7 @@
void pullAndMatchEventsLocked(const int64_t timestampNs, ConditionState condition);
- void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
+ void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData,
int64_t originalPullTimeNs, int64_t eventElapsedTimeNs,
ConditionState condition);
@@ -244,6 +244,7 @@
FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled);
FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
FRIEND_TEST(ValueMetricProducerTest, TestFirstBucket);
+ FRIEND_TEST(ValueMetricProducerTest, TestFullBucketResetWhenLastBucketInvalid);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index 52d5ffc..f7e32d4 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define DEBUG true // STOPSHIP if true
+#define DEBUG false // STOPSHIP if true
#include "Log.h"
#include "ShellSubscriber.h"
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index ef3643f..3dff7f5 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@
IPCThreadState* ipc = IPCThreadState::self();
ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
- true /* erase_data */, ADB_DUMP, FAST, &output);
+ true /* erase_data */, ADB_DUMP, NO_TIME_CONSTRAINTS, &output);
ConfigMetricsReportList reports;
reports.ParseFromArray(output.data(), output.size());
EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index cdb5a78..b316562 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -75,7 +75,7 @@
mAllMetricProducers[0]->getCurrentBucketNum();
EXPECT_GT(startBucketNum, (int64_t)0);
- // When creating the config, the gauge metric producer should register the alarm at the
+ // When creating the config, the value metric producer should register the alarm at the
// end of the current bucket.
EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
@@ -140,32 +140,30 @@
EXPECT_EQ(1 /* subsystem name field */,
data.dimensions_in_what().value_tuple().dimensions_value(0).field());
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
- EXPECT_EQ(5, data.bucket_info_size());
+ // We have 4 buckets, the first one was incomplete since the condition was unknown.
+ EXPECT_EQ(4, data.bucket_info_size());
- EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
- EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_EQ(1, data.bucket_info(0).values_size());
- EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
- EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
EXPECT_EQ(1, data.bucket_info(1).values_size());
- EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
- EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
EXPECT_EQ(1, data.bucket_info(2).values_size());
- EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
- EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
EXPECT_EQ(1, data.bucket_info(3).values_size());
-
- EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
- EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
- EXPECT_EQ(1, data.bucket_info(4).values_size());
}
TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
auto config = CreateStatsdConfig();
int64_t baseTimeNs = getElapsedRealtimeNs();
+ // 10 mins == 2 bucket durations.
int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
int64_t bucketSizeNs =
TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
@@ -181,7 +179,7 @@
mAllMetricProducers[0]->getCurrentBucketNum();
EXPECT_GT(startBucketNum, (int64_t)0);
- // When creating the config, the gauge metric producer should register the alarm at the
+ // When creating the config, the value metric producer should register the alarm at the
// end of the current bucket.
EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
EXPECT_EQ(bucketSizeNs,
@@ -203,15 +201,18 @@
configAddedTimeNs + 75);
processor->OnLogEvent(screenOffEvent.get());
- // Pulling alarm arrives late by 2 buckets and 1 ns.
+ // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
+ // future, data will be skipped.
processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+ // This screen state change will start a new bucket.
screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
configAddedTimeNs + 4 * bucketSizeNs + 65);
processor->OnLogEvent(screenOnEvent.get());
- // Pulling alarm arrives late by one bucket size + 21ns.
+ // The alarm is delayed but we already created a bucket thanks to the screen state condition.
+ // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
@@ -249,8 +250,8 @@
EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
EXPECT_EQ(3, data.bucket_info_size());
- EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
- EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
EXPECT_EQ(1, data.bucket_info(0).values_size());
EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index e5e4534..90b9e81 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2500,6 +2500,37 @@
EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
}
+TEST(ValueMetricProducerTest, TestFullBucketResetWhenLastBucketInvalid) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+ EXPECT_CALL(*pullerManager, Pull(tagId, _))
+ // Initialization.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(bucketStartTimeNs, 1));
+ return true;
+ }))
+ // notifyAppUpgrade.
+ .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+ data->clear();
+ data->push_back(ValueMetricProducerTestHelper::createEvent(
+ bucketStartTimeNs + bucketSizeNs / 2, 10));
+ return true;
+ }));
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
+ ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
+
+ valueProducer->notifyAppUpgrade(bucketStartTimeNs + bucketSizeNs / 2, "com.foo", 10000, 1);
+ ASSERT_EQ(1UL, valueProducer->mCurrentFullBucket.size());
+
+ vector<shared_ptr<LogEvent>> allData;
+ allData.push_back(ValueMetricProducerTestHelper::createEvent(bucket3StartTimeNs + 1, 4));
+ valueProducer->onDataPulled(allData, /** fails */ false, bucket3StartTimeNs + 1);
+ ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size());
+}
+
TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index c6a3d80..b3f0037 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -278,227 +278,16 @@
Landroid/net/wifi/IWifiScanner$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/IWifiScanner;
Landroid/net/wifi/p2p/IWifiP2pManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/wifi/p2p/IWifiP2pManager;
Landroid/nfc/INfcAdapter$Stub;->TRANSACTION_enable:I
-Landroid/os/AsyncResult;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Throwable;)V
-Landroid/os/AsyncResult;->exception:Ljava/lang/Throwable;
-Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;)Landroid/os/AsyncResult;
-Landroid/os/AsyncResult;->forMessage(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)Landroid/os/AsyncResult;
-Landroid/os/AsyncResult;->result:Ljava/lang/Object;
-Landroid/os/AsyncResult;->userObj:Ljava/lang/Object;
-Landroid/os/AsyncTask;->mFuture:Ljava/util/concurrent/FutureTask;
-Landroid/os/AsyncTask;->mStatus:Landroid/os/AsyncTask$Status;
-Landroid/os/AsyncTask;->mTaskInvoked:Ljava/util/concurrent/atomic/AtomicBoolean;
-Landroid/os/AsyncTask;->mWorker:Landroid/os/AsyncTask$WorkerRunnable;
-Landroid/os/AsyncTask;->sDefaultExecutor:Ljava/util/concurrent/Executor;
-Landroid/os/AsyncTask;->setDefaultExecutor(Ljava/util/concurrent/Executor;)V
-Landroid/os/BaseBundle;->isParcelled()Z
-Landroid/os/BaseBundle;->mMap:Landroid/util/ArrayMap;
-Landroid/os/BaseBundle;->mParcelledData:Landroid/os/Parcel;
-Landroid/os/BaseBundle;->unparcel()V
-Landroid/os/BatteryManager;->EXTRA_CHARGE_COUNTER:Ljava/lang/String;
-Landroid/os/BatteryManager;->EXTRA_INVALID_CHARGER:Ljava/lang/String;
-Landroid/os/BatteryManager;->EXTRA_MAX_CHARGING_CURRENT:Ljava/lang/String;
-Landroid/os/BatteryManager;->EXTRA_MAX_CHARGING_VOLTAGE:Ljava/lang/String;
-Landroid/os/BatteryStats$Counter;->getCountLocked(I)I
-Landroid/os/BatteryStats$HistoryItem;-><init>()V
-Landroid/os/BatteryStats$HistoryItem;->batteryHealth:B
-Landroid/os/BatteryStats$HistoryItem;->batteryLevel:B
-Landroid/os/BatteryStats$HistoryItem;->batteryPlugType:B
-Landroid/os/BatteryStats$HistoryItem;->batteryStatus:B
-Landroid/os/BatteryStats$HistoryItem;->batteryVoltage:C
-Landroid/os/BatteryStats$HistoryItem;->cmd:B
-Landroid/os/BatteryStats$HistoryItem;->CMD_UPDATE:B
-Landroid/os/BatteryStats$HistoryItem;->states2:I
-Landroid/os/BatteryStats$HistoryItem;->states:I
-Landroid/os/BatteryStats$HistoryItem;->time:J
-Landroid/os/BatteryStats$Timer;->getCountLocked(I)I
-Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
-Landroid/os/BatteryStats$Uid$Pkg$Serv;->getLaunches(I)I
-Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStarts(I)I
-Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStartTime(JI)J
-Landroid/os/BatteryStats$Uid$Pkg;->getServiceStats()Landroid/util/ArrayMap;
-Landroid/os/BatteryStats$Uid$Pkg;->getWakeupAlarmStats()Landroid/util/ArrayMap;
Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;-><init>()V
-Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->overTime:J
-Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->type:I
-Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;->usedTime:J
-Landroid/os/BatteryStats$Uid$Proc;->countExcessivePowers()I
-Landroid/os/BatteryStats$Uid$Proc;->getExcessivePower(I)Landroid/os/BatteryStats$Uid$Proc$ExcessivePower;
-Landroid/os/BatteryStats$Uid$Proc;->getForegroundTime(I)J
-Landroid/os/BatteryStats$Uid$Proc;->getStarts(I)I
-Landroid/os/BatteryStats$Uid$Proc;->getSystemTime(I)J
-Landroid/os/BatteryStats$Uid$Proc;->getUserTime(I)J
-Landroid/os/BatteryStats$Uid$Sensor;->getHandle()I
-Landroid/os/BatteryStats$Uid$Sensor;->getSensorTime()Landroid/os/BatteryStats$Timer;
-Landroid/os/BatteryStats$Uid$Sensor;->GPS:I
-Landroid/os/BatteryStats$Uid$Wakelock;->getWakeTime(I)Landroid/os/BatteryStats$Timer;
Landroid/os/BatteryStats$Uid;-><init>()V
-Landroid/os/BatteryStats$Uid;->getAudioTurnedOnTimer()Landroid/os/BatteryStats$Timer;
-Landroid/os/BatteryStats$Uid;->getFullWifiLockTime(JI)J
-Landroid/os/BatteryStats$Uid;->getMobileRadioActiveTime(I)J
-Landroid/os/BatteryStats$Uid;->getNetworkActivityBytes(II)J
-Landroid/os/BatteryStats$Uid;->getPackageStats()Landroid/util/ArrayMap;
-Landroid/os/BatteryStats$Uid;->getProcessStats()Landroid/util/ArrayMap;
-Landroid/os/BatteryStats$Uid;->getSensorStats()Landroid/util/SparseArray;
-Landroid/os/BatteryStats$Uid;->getUid()I
-Landroid/os/BatteryStats$Uid;->getVideoTurnedOnTimer()Landroid/os/BatteryStats$Timer;
-Landroid/os/BatteryStats$Uid;->getWakelockStats()Landroid/util/ArrayMap;
-Landroid/os/BatteryStats$Uid;->getWifiBatchedScanTime(IJI)J
-Landroid/os/BatteryStats$Uid;->getWifiMulticastTime(JI)J
-Landroid/os/BatteryStats$Uid;->getWifiRunningTime(JI)J
-Landroid/os/BatteryStats$Uid;->getWifiScanTime(JI)J
-Landroid/os/BatteryStats;->computeBatteryRealtime(JI)J
-Landroid/os/BatteryStats;->computeBatteryTimeRemaining(J)J
-Landroid/os/BatteryStats;->computeBatteryUptime(JI)J
-Landroid/os/BatteryStats;->computeChargeTimeRemaining(J)J
-Landroid/os/BatteryStats;->dumpLine(Ljava/io/PrintWriter;ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V
-Landroid/os/BatteryStats;->getBatteryUptime(J)J
-Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J
-Landroid/os/BatteryStats;->getNextHistoryLocked(Landroid/os/BatteryStats$HistoryItem;)Z
-Landroid/os/BatteryStats;->getPhoneOnTime(JI)J
-Landroid/os/BatteryStats;->getPhoneSignalStrengthTime(IJI)J
-Landroid/os/BatteryStats;->getScreenBrightnessTime(IJI)J
-Landroid/os/BatteryStats;->getScreenOnTime(JI)J
-Landroid/os/BatteryStats;->getUidStats()Landroid/util/SparseArray;
-Landroid/os/BatteryStats;->getWifiOnTime(JI)J
-Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I
-Landroid/os/BatteryStats;->NUM_SCREEN_BRIGHTNESS_BINS:I
-Landroid/os/BatteryStats;->startIteratingHistoryLocked()Z
-Landroid/os/BatteryStats;->STATS_CURRENT:I
-Landroid/os/BatteryStats;->WAKE_TYPE_PARTIAL:I
-Landroid/os/Binder;->execTransact(IJJI)Z
-Landroid/os/Binder;->mObject:J
-Landroid/os/Broadcaster;-><init>()V
-Landroid/os/Broadcaster;->broadcast(Landroid/os/Message;)V
-Landroid/os/Broadcaster;->cancelRequest(ILandroid/os/Handler;I)V
-Landroid/os/Broadcaster;->request(ILandroid/os/Handler;I)V
-Landroid/os/Build$VERSION;->ACTIVE_CODENAMES:[Ljava/lang/String;
-Landroid/os/Build;->getLong(Ljava/lang/String;)J
-Landroid/os/Build;->getString(Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/Build;->IS_DEBUGGABLE:Z
-Landroid/os/Bundle;->filterValues()Landroid/os/Bundle;
-Landroid/os/Bundle;->forPair(Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle;
-Landroid/os/Bundle;->getIBinder(Ljava/lang/String;)Landroid/os/IBinder;
-Landroid/os/Bundle;->getSize()I
-Landroid/os/Bundle;->putIBinder(Ljava/lang/String;Landroid/os/IBinder;)V
-Landroid/os/Bundle;->putParcelableList(Ljava/lang/String;Ljava/util/List;)V
-Landroid/os/Bundle;->setDefusable(Landroid/os/Bundle;Z)Landroid/os/Bundle;
-Landroid/os/Debug$MemoryInfo;->dalvikPrivateClean:I
-Landroid/os/Debug$MemoryInfo;->dalvikRss:I
-Landroid/os/Debug$MemoryInfo;->dalvikSharedClean:I
-Landroid/os/Debug$MemoryInfo;->dalvikSwappablePss:I
-Landroid/os/Debug$MemoryInfo;->dalvikSwappedOut:I
-Landroid/os/Debug$MemoryInfo;->dalvikSwappedOutPss:I
-Landroid/os/Debug$MemoryInfo;->getOtherLabel(I)Ljava/lang/String;
-Landroid/os/Debug$MemoryInfo;->getOtherPrivate(I)I
-Landroid/os/Debug$MemoryInfo;->getOtherPrivateDirty(I)I
-Landroid/os/Debug$MemoryInfo;->getOtherPss(I)I
-Landroid/os/Debug$MemoryInfo;->getOtherSharedDirty(I)I
-Landroid/os/Debug$MemoryInfo;->getSummaryCode()I
-Landroid/os/Debug$MemoryInfo;->getSummaryGraphics()I
-Landroid/os/Debug$MemoryInfo;->getSummaryJavaHeap()I
-Landroid/os/Debug$MemoryInfo;->getSummaryNativeHeap()I
-Landroid/os/Debug$MemoryInfo;->getSummaryPrivateOther()I
-Landroid/os/Debug$MemoryInfo;->getSummaryStack()I
-Landroid/os/Debug$MemoryInfo;->getSummarySystem()I
-Landroid/os/Debug$MemoryInfo;->getTotalUss()I
-Landroid/os/Debug$MemoryInfo;->hasSwappedOutPss:Z
-Landroid/os/Debug$MemoryInfo;->nativePrivateClean:I
-Landroid/os/Debug$MemoryInfo;->nativeRss:I
-Landroid/os/Debug$MemoryInfo;->nativeSharedClean:I
-Landroid/os/Debug$MemoryInfo;->nativeSwappablePss:I
-Landroid/os/Debug$MemoryInfo;->nativeSwappedOut:I
-Landroid/os/Debug$MemoryInfo;->nativeSwappedOutPss:I
-Landroid/os/Debug$MemoryInfo;->NUM_DVK_STATS:I
-Landroid/os/Debug$MemoryInfo;->NUM_OTHER_STATS:I
-Landroid/os/Debug$MemoryInfo;->otherPrivateClean:I
-Landroid/os/Debug$MemoryInfo;->otherRss:I
-Landroid/os/Debug$MemoryInfo;->otherSharedClean:I
-Landroid/os/Debug$MemoryInfo;->otherStats:[I
-Landroid/os/Debug$MemoryInfo;->otherSwappablePss:I
-Landroid/os/Debug$MemoryInfo;->otherSwappedOut:I
-Landroid/os/Debug$MemoryInfo;->otherSwappedOutPss:I
-Landroid/os/Debug;-><init>()V
-Landroid/os/Debug;->countInstancesOfClass(Ljava/lang/Class;)J
-Landroid/os/Debug;->dumpNativeHeap(Ljava/io/FileDescriptor;)V
-Landroid/os/Debug;->dumpReferenceTables()V
-Landroid/os/Debug;->getCaller()Ljava/lang/String;
-Landroid/os/Debug;->getCallers(I)Ljava/lang/String;
-Landroid/os/Debug;->getMemInfo([J)V
-Landroid/os/Debug;->getMemoryInfo(ILandroid/os/Debug$MemoryInfo;)V
-Landroid/os/DropBoxManager;->mService:Lcom/android/internal/os/IDropBoxManagerService;
-Landroid/os/Environment$UserEnvironment;-><init>(I)V
-Landroid/os/Environment$UserEnvironment;->getExternalDirs()[Ljava/io/File;
-Landroid/os/Environment$UserEnvironment;->getExternalStorageDirectory()Ljava/io/File;
-Landroid/os/Environment$UserEnvironment;->getExternalStoragePublicDirectory(Ljava/lang/String;)Ljava/io/File;
-Landroid/os/Environment;->buildExternalStorageAndroidDataDirs()[Ljava/io/File;
-Landroid/os/Environment;->buildExternalStorageAppCacheDirs(Ljava/lang/String;)[Ljava/io/File;
-Landroid/os/Environment;->buildExternalStorageAppDataDirs(Ljava/lang/String;)[Ljava/io/File;
-Landroid/os/Environment;->buildExternalStorageAppFilesDirs(Ljava/lang/String;)[Ljava/io/File;
-Landroid/os/Environment;->buildExternalStorageAppMediaDirs(Ljava/lang/String;)[Ljava/io/File;
-Landroid/os/Environment;->buildExternalStorageAppObbDirs(Ljava/lang/String;)[Ljava/io/File;
-Landroid/os/Environment;->buildPaths([Ljava/io/File;[Ljava/lang/String;)[Ljava/io/File;
-Landroid/os/Environment;->getDataSystemDirectory()Ljava/io/File;
-Landroid/os/Environment;->getLegacyExternalStorageDirectory()Ljava/io/File;
-Landroid/os/Environment;->getLegacyExternalStorageObbDirectory()Ljava/io/File;
-Landroid/os/Environment;->initForCurrentUser()V
-Landroid/os/Environment;->maybeTranslateEmulatedPathToInternal(Ljava/io/File;)Ljava/io/File;
-Landroid/os/Environment;->sCurrentUser:Landroid/os/Environment$UserEnvironment;
-Landroid/os/FileObserver$ObserverThread;->onEvent(IILjava/lang/String;)V
-Landroid/os/FileObserver;->s_observerThread:Landroid/os/FileObserver$ObserverThread;
-Landroid/os/FileUtils;-><init>()V
-Landroid/os/FileUtils;->checksumCrc32(Ljava/io/File;)J
-Landroid/os/FileUtils;->copyFile(Ljava/io/File;Ljava/io/File;)Z
-Landroid/os/FileUtils;->copyToFile(Ljava/io/InputStream;Ljava/io/File;)Z
-Landroid/os/FileUtils;->deleteContents(Ljava/io/File;)Z
-Landroid/os/FileUtils;->deleteOlderFiles(Ljava/io/File;IJ)Z
-Landroid/os/FileUtils;->isFilenameSafe(Ljava/io/File;)Z
-Landroid/os/FileUtils;->readTextFile(Ljava/io/File;ILjava/lang/String;)Ljava/lang/String;
-Landroid/os/FileUtils;->setPermissions(Ljava/io/File;III)I
-Landroid/os/FileUtils;->setPermissions(Ljava/io/FileDescriptor;III)I
-Landroid/os/FileUtils;->setPermissions(Ljava/lang/String;III)I
-Landroid/os/FileUtils;->stringToFile(Ljava/io/File;Ljava/lang/String;)V
-Landroid/os/FileUtils;->stringToFile(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/os/FileUtils;->sync(Ljava/io/FileOutputStream;)Z
-Landroid/os/Handler;-><init>(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V
-Landroid/os/Handler;-><init>(Z)V
-Landroid/os/Handler;->getIMessenger()Landroid/os/IMessenger;
-Landroid/os/Handler;->getMain()Landroid/os/Handler;
-Landroid/os/Handler;->getPostMessage(Ljava/lang/Runnable;Ljava/lang/Object;)Landroid/os/Message;
-Landroid/os/Handler;->mCallback:Landroid/os/Handler$Callback;
-Landroid/os/Handler;->mLooper:Landroid/os/Looper;
-Landroid/os/Handler;->mMessenger:Landroid/os/IMessenger;
-Landroid/os/HwBinder;->reportSyspropChanged()V
-Landroid/os/HwParcel;-><init>(Z)V
-Landroid/os/HwRemoteBinder;-><init>()V
Landroid/os/IBatteryPropertiesRegistrar$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/os/IBinder;->SYSPROPS_TRANSACTION:I
Landroid/os/IDeviceIdentifiersPolicyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdentifiersPolicyService;
Landroid/os/IDeviceIdleController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IDeviceIdleController;
-Landroid/os/IDeviceIdleController;->addPowerSaveTempWhitelistApp(Ljava/lang/String;JILjava/lang/String;)V
Landroid/os/IDeviceIdleController;->getAppIdTempWhitelist()[I
Landroid/os/IDeviceIdleController;->getFullPowerWhitelistExceptIdle()[Ljava/lang/String;
Landroid/os/INetworkManagementService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/INetworkManagementService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/INetworkManagementService;
-Landroid/os/INetworkManagementService;->clearInterfaceAddresses(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->disableIpv6(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->disableNat(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->enableIpv6(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->enableNat(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->getInterfaceConfig(Ljava/lang/String;)Landroid/net/InterfaceConfiguration;
-Landroid/os/INetworkManagementService;->getIpForwardingEnabled()Z
-Landroid/os/INetworkManagementService;->isBandwidthControlEnabled()Z
-Landroid/os/INetworkManagementService;->isTetheringStarted()Z
Landroid/os/INetworkManagementService;->listTetheredInterfaces()[Ljava/lang/String;
-Landroid/os/INetworkManagementService;->registerObserver(Landroid/net/INetworkManagementEventObserver;)V
-Landroid/os/INetworkManagementService;->setInterfaceConfig(Ljava/lang/String;Landroid/net/InterfaceConfiguration;)V
-Landroid/os/INetworkManagementService;->setInterfaceIpv6PrivacyExtensions(Ljava/lang/String;Z)V
-Landroid/os/INetworkManagementService;->setIpForwardingEnabled(Z)V
-Landroid/os/INetworkManagementService;->setIPv6AddrGenMode(Ljava/lang/String;I)V
-Landroid/os/INetworkManagementService;->startTethering([Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->stopTethering()V
-Landroid/os/INetworkManagementService;->tetherInterface(Ljava/lang/String;)V
-Landroid/os/INetworkManagementService;->unregisterObserver(Landroid/net/INetworkManagementEventObserver;)V
-Landroid/os/INetworkManagementService;->untetherInterface(Ljava/lang/String;)V
Landroid/os/IPermissionController$Stub$Proxy;->checkPermission(Ljava/lang/String;II)Z
Landroid/os/IPermissionController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPermissionController;
Landroid/os/IPowerManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
@@ -506,282 +295,21 @@
Landroid/os/IPowerManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IPowerManager;
Landroid/os/IPowerManager$Stub;->TRANSACTION_acquireWakeLock:I
Landroid/os/IPowerManager$Stub;->TRANSACTION_goToSleep:I
-Landroid/os/IPowerManager;->goToSleep(JII)V
-Landroid/os/IPowerManager;->isInteractive()Z
-Landroid/os/IPowerManager;->reboot(ZLjava/lang/String;Z)V
Landroid/os/IPowerManager;->releaseWakeLock(Landroid/os/IBinder;I)V
-Landroid/os/IPowerManager;->userActivity(JII)V
Landroid/os/IRecoverySystem$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IRecoverySystem;
Landroid/os/IRemoteCallback$Stub;-><init>()V
-Landroid/os/IRemoteCallback;->sendResult(Landroid/os/Bundle;)V
-Landroid/os/IServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
-Landroid/os/IServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
Landroid/os/IUpdateEngine$Stub;-><init>()V
Landroid/os/IUpdateEngineCallback;->onStatusUpdate(IF)V
Landroid/os/IUserManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/IUserManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IUserManager;
-Landroid/os/IUserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
Landroid/os/IVibratorService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IVibratorService;
-Landroid/os/LocaleList;->setDefault(Landroid/os/LocaleList;I)V
-Landroid/os/Looper;->mLogging:Landroid/util/Printer;
-Landroid/os/Looper;->mQueue:Landroid/os/MessageQueue;
-Landroid/os/Looper;->setTraceTag(J)V
-Landroid/os/Looper;->sMainLooper:Landroid/os/Looper;
-Landroid/os/Looper;->sThreadLocal:Ljava/lang/ThreadLocal;
-Landroid/os/MemoryFile;->deactivate()V
-Landroid/os/MemoryFile;->getFileDescriptor()Ljava/io/FileDescriptor;
-Landroid/os/MemoryFile;->getSize(Ljava/io/FileDescriptor;)I
-Landroid/os/MemoryFile;->native_get_size(Ljava/io/FileDescriptor;)I
-Landroid/os/MemoryFile;->native_pin(Ljava/io/FileDescriptor;Z)Z
-Landroid/os/Message;->callback:Ljava/lang/Runnable;
-Landroid/os/Message;->flags:I
-Landroid/os/Message;->markInUse()V
-Landroid/os/Message;->next:Landroid/os/Message;
-Landroid/os/Message;->recycleUnchecked()V
-Landroid/os/Message;->setCallback(Ljava/lang/Runnable;)Landroid/os/Message;
-Landroid/os/Message;->target:Landroid/os/Handler;
-Landroid/os/Message;->toString(J)Ljava/lang/String;
-Landroid/os/Message;->when:J
-Landroid/os/MessageQueue;->dispatchEvents(II)I
-Landroid/os/MessageQueue;->hasMessages(Landroid/os/Handler;Ljava/lang/Runnable;Ljava/lang/Object;)Z
-Landroid/os/MessageQueue;->mIdleHandlers:Ljava/util/ArrayList;
-Landroid/os/MessageQueue;->mMessages:Landroid/os/Message;
-Landroid/os/MessageQueue;->mNextBarrierToken:I
-Landroid/os/MessageQueue;->mPtr:J
-Landroid/os/MessageQueue;->mQuitAllowed:Z
-Landroid/os/MessageQueue;->nativePollOnce(JI)V
-Landroid/os/MessageQueue;->next()Landroid/os/Message;
Landroid/os/Parcel$ReadWriteHelper;-><init>()V
-Landroid/os/Parcel;->getGlobalAllocCount()J
-Landroid/os/Parcel;->getGlobalAllocSize()J
-Landroid/os/Parcel;->mNativePtr:J
-Landroid/os/Parcel;->readArrayMap(Landroid/util/ArrayMap;Ljava/lang/ClassLoader;)V
-Landroid/os/Parcel;->readArraySet(Ljava/lang/ClassLoader;)Landroid/util/ArraySet;
-Landroid/os/Parcel;->readBlob()[B
-Landroid/os/Parcel;->readCharSequence()Ljava/lang/CharSequence;
-Landroid/os/Parcel;->readCreator(Landroid/os/Parcelable$Creator;Ljava/lang/ClassLoader;)Landroid/os/Parcelable;
-Landroid/os/Parcel;->readExceptionCode()I
-Landroid/os/Parcel;->readParcelableCreator(Ljava/lang/ClassLoader;)Landroid/os/Parcelable$Creator;
-Landroid/os/Parcel;->readRawFileDescriptor()Ljava/io/FileDescriptor;
-Landroid/os/Parcel;->readStringArray()[Ljava/lang/String;
-Landroid/os/Parcel;->writeArrayMap(Landroid/util/ArrayMap;)V
-Landroid/os/Parcel;->writeArraySet(Landroid/util/ArraySet;)V
-Landroid/os/Parcel;->writeBlob([B)V
-Landroid/os/Parcel;->writeCharSequence(Ljava/lang/CharSequence;)V
-Landroid/os/Parcel;->writeParcelableCreator(Landroid/os/Parcelable;)V
-Landroid/os/ParcelableParcel;-><init>(Ljava/lang/ClassLoader;)V
-Landroid/os/ParcelableParcel;->CREATOR:Landroid/os/Parcelable$ClassLoaderCreator;
-Landroid/os/ParcelableParcel;->getClassLoader()Ljava/lang/ClassLoader;
-Landroid/os/ParcelableParcel;->getParcel()Landroid/os/Parcel;
-Landroid/os/ParcelFileDescriptor;-><init>(Ljava/io/FileDescriptor;)V
-Landroid/os/ParcelFileDescriptor;->fromData([BLjava/lang/String;)Landroid/os/ParcelFileDescriptor;
-Landroid/os/ParcelFileDescriptor;->seekTo(J)J
-Landroid/os/PerformanceCollector;-><init>()V
-Landroid/os/PerformanceCollector;->beginSnapshot(Ljava/lang/String;)V
-Landroid/os/PerformanceCollector;->endSnapshot()Landroid/os/Bundle;
-Landroid/os/PerformanceCollector;->startTiming(Ljava/lang/String;)V
-Landroid/os/PerformanceCollector;->stopTiming(Ljava/lang/String;)Landroid/os/Bundle;
-Landroid/os/PowerManager$WakeLock;->mFlags:I
-Landroid/os/PowerManager$WakeLock;->mTag:Ljava/lang/String;
-Landroid/os/PowerManager;->ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED:Ljava/lang/String;
-Landroid/os/PowerManager;->ACTION_POWER_SAVE_MODE_CHANGING:Ljava/lang/String;
-Landroid/os/PowerManager;->BRIGHTNESS_ON:I
-Landroid/os/PowerManager;->EXTRA_POWER_SAVE_MODE:Ljava/lang/String;
-Landroid/os/PowerManager;->getDefaultScreenBrightnessSetting()I
-Landroid/os/PowerManager;->getMaximumScreenBrightnessSetting()I
-Landroid/os/PowerManager;->getMinimumScreenBrightnessSetting()I
-Landroid/os/PowerManager;->goToSleep(JII)V
-Landroid/os/PowerManager;->GO_TO_SLEEP_REASON_TIMEOUT:I
-Landroid/os/PowerManager;->isLightDeviceIdleMode()Z
-Landroid/os/PowerManager;->mService:Landroid/os/IPowerManager;
-Landroid/os/PowerManager;->validateWakeLockParameters(ILjava/lang/String;)V
-Landroid/os/PowerManager;->wakeUp(JLjava/lang/String;)V
-Landroid/os/Process;->DRM_UID:I
-Landroid/os/Process;->getFreeMemory()J
-Landroid/os/Process;->getParentPid(I)I
-Landroid/os/Process;->getPids(Ljava/lang/String;[I)[I
-Landroid/os/Process;->getPidsForCommands([Ljava/lang/String;)[I
-Landroid/os/Process;->getPss(I)J
-Landroid/os/Process;->getTotalMemory()J
-Landroid/os/Process;->getUidForPid(I)I
-Landroid/os/Process;->isIsolated(I)Z
-Landroid/os/Process;->LOG_UID:I
-Landroid/os/Process;->MEDIA_UID:I
-Landroid/os/Process;->myPpid()I
-Landroid/os/Process;->NFC_UID:I
-Landroid/os/Process;->parseProcLine([BII[I[Ljava/lang/String;[J[F)Z
-Landroid/os/Process;->PROC_COMBINE:I
-Landroid/os/Process;->PROC_OUT_FLOAT:I
-Landroid/os/Process;->PROC_OUT_LONG:I
-Landroid/os/Process;->PROC_OUT_STRING:I
-Landroid/os/Process;->PROC_PARENS:I
-Landroid/os/Process;->PROC_QUOTES:I
-Landroid/os/Process;->PROC_SPACE_TERM:I
-Landroid/os/Process;->PROC_TAB_TERM:I
-Landroid/os/Process;->PROC_TERM_MASK:I
-Landroid/os/Process;->PROC_ZERO_TERM:I
-Landroid/os/Process;->readProcFile(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z
-Landroid/os/Process;->readProcLines(Ljava/lang/String;[Ljava/lang/String;[J)V
-Landroid/os/Process;->setArgV0(Ljava/lang/String;)V
-Landroid/os/Process;->setProcessGroup(II)V
-Landroid/os/Process;->VPN_UID:I
-Landroid/os/Process;->WIFI_UID:I
-Landroid/os/RecoverySystem;->verifyPackageCompatibility(Ljava/io/InputStream;)Z
-Landroid/os/Registrant;-><init>(Landroid/os/Handler;ILjava/lang/Object;)V
-Landroid/os/Registrant;->clear()V
-Landroid/os/Registrant;->messageForRegistrant()Landroid/os/Message;
-Landroid/os/Registrant;->notifyRegistrant()V
-Landroid/os/Registrant;->notifyRegistrant(Landroid/os/AsyncResult;)V
-Landroid/os/Registrant;->notifyResult(Ljava/lang/Object;)V
Landroid/os/RegistrantList;-><init>()V
-Landroid/os/RegistrantList;->add(Landroid/os/Handler;ILjava/lang/Object;)V
-Landroid/os/RegistrantList;->add(Landroid/os/Registrant;)V
-Landroid/os/RegistrantList;->addUnique(Landroid/os/Handler;ILjava/lang/Object;)V
-Landroid/os/RegistrantList;->notifyRegistrants()V
-Landroid/os/RegistrantList;->notifyRegistrants(Landroid/os/AsyncResult;)V
-Landroid/os/RegistrantList;->notifyResult(Ljava/lang/Object;)V
-Landroid/os/RegistrantList;->remove(Landroid/os/Handler;)V
-Landroid/os/RegistrantList;->removeCleared()V
-Landroid/os/RegistrantList;->size()I
-Landroid/os/RemoteCallbackList;->mCallbacks:Landroid/util/ArrayMap;
-Landroid/os/RemoteException;->rethrowFromSystemServer()Ljava/lang/RuntimeException;
-Landroid/os/SELinux;->checkSELinuxAccess(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z
-Landroid/os/SELinux;->getContext()Ljava/lang/String;
-Landroid/os/SELinux;->getFileContext(Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SELinux;->getPidContext(I)Ljava/lang/String;
-Landroid/os/SELinux;->isSELinuxEnabled()Z
-Landroid/os/SELinux;->isSELinuxEnforced()Z
-Landroid/os/SELinux;->restoreconRecursive(Ljava/io/File;)Z
Landroid/os/ServiceManager;-><init>()V
-Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;)V
-Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;Z)V
-Landroid/os/ServiceManager;->addService(Ljava/lang/String;Landroid/os/IBinder;ZI)V
-Landroid/os/ServiceManager;->checkService(Ljava/lang/String;)Landroid/os/IBinder;
-Landroid/os/ServiceManager;->getIServiceManager()Landroid/os/IServiceManager;
-Landroid/os/ServiceManager;->getService(Ljava/lang/String;)Landroid/os/IBinder;
-Landroid/os/ServiceManager;->listServices()[Ljava/lang/String;
-Landroid/os/ServiceManager;->sCache:Ljava/util/Map;
-Landroid/os/ServiceManager;->sServiceManager:Landroid/os/IServiceManager;
-Landroid/os/ServiceManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/os/IServiceManager;
-Landroid/os/ServiceManagerProxy;->getService(Ljava/lang/String;)Landroid/os/IBinder;
-Landroid/os/ServiceManagerProxy;->mRemote:Landroid/os/IBinder;
-Landroid/os/SharedMemory;->getFd()I
-Landroid/os/ShellCommand;->peekNextArg()Ljava/lang/String;
-Landroid/os/StatFs;->mStat:Landroid/system/StructStatVfs;
Landroid/os/storage/IObbActionListener$Stub;-><init>()V
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
Landroid/os/storage/StorageEventListener;-><init>()V
-Landroid/os/StrictMode$Span;->finish()V
-Landroid/os/StrictMode$ThreadPolicy;->mask:I
-Landroid/os/StrictMode$VmPolicy$Builder;->mMask:I
-Landroid/os/StrictMode$VmPolicy;->mask:I
-Landroid/os/StrictMode;->disableDeathOnFileUriExposure()V
-Landroid/os/StrictMode;->enableDeathOnFileUriExposure()V
-Landroid/os/StrictMode;->enterCriticalSpan(Ljava/lang/String;)Landroid/os/StrictMode$Span;
-Landroid/os/StrictMode;->getThreadPolicyMask()I
-Landroid/os/StrictMode;->incrementExpectedActivityCount(Ljava/lang/Class;)V
-Landroid/os/StrictMode;->onBinderStrictModePolicyChange(I)V
-Landroid/os/StrictMode;->onWebViewMethodCalledOnWrongThread(Ljava/lang/Throwable;)V
-Landroid/os/StrictMode;->sLastVmViolationTime:Ljava/util/HashMap;
-Landroid/os/StrictMode;->sWindowManager:Landroid/util/Singleton;
-Landroid/os/StrictMode;->violationsBeingTimed:Ljava/lang/ThreadLocal;
-Landroid/os/SystemClock;-><init>()V
-Landroid/os/SystemClock;->currentThreadTimeMicro()J
-Landroid/os/SystemClock;->currentTimeMicro()J
-Landroid/os/SystemProperties;-><init>()V
-Landroid/os/SystemProperties;->addChangeCallback(Ljava/lang/Runnable;)V
-Landroid/os/SystemProperties;->native_get(Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/SystemProperties;->native_get_long(Ljava/lang/String;J)J
-Landroid/os/SystemProperties;->PROP_NAME_MAX:I
-Landroid/os/SystemProperties;->reportSyspropChanged()V
-Landroid/os/SystemProperties;->sChangeCallbacks:Ljava/util/ArrayList;
-Landroid/os/SystemProperties;->set(Ljava/lang/String;Ljava/lang/String;)V
-Landroid/os/SystemService;->start(Ljava/lang/String;)V
-Landroid/os/SystemService;->stop(Ljava/lang/String;)V
-Landroid/os/SystemVibrator;-><init>()V
-Landroid/os/SystemVibrator;-><init>(Landroid/content/Context;)V
-Landroid/os/Trace;->asyncTraceBegin(JLjava/lang/String;I)V
-Landroid/os/Trace;->asyncTraceEnd(JLjava/lang/String;I)V
-Landroid/os/Trace;->isTagEnabled(J)Z
-Landroid/os/Trace;->nativeGetEnabledTags()J
-Landroid/os/Trace;->sEnabledTags:J
-Landroid/os/Trace;->setAppTracingAllowed(Z)V
-Landroid/os/Trace;->traceBegin(JLjava/lang/String;)V
-Landroid/os/Trace;->traceCounter(JLjava/lang/String;I)V
-Landroid/os/Trace;->traceEnd(J)V
-Landroid/os/Trace;->TRACE_TAG_APP:J
-Landroid/os/Trace;->TRACE_TAG_VIEW:J
-Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/UEventObserver$UEvent;->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-Landroid/os/UEventObserver;-><init>()V
-Landroid/os/UEventObserver;->onUEvent(Landroid/os/UEventObserver$UEvent;)V
-Landroid/os/UEventObserver;->startObserving(Ljava/lang/String;)V
-Landroid/os/UEventObserver;->stopObserving()V
-Landroid/os/UpdateLock;->acquire()V
-Landroid/os/UpdateLock;->isHeld()Z
-Landroid/os/UpdateLock;->NOW_IS_CONVENIENT:Ljava/lang/String;
-Landroid/os/UpdateLock;->release()V
-Landroid/os/UpdateLock;->TIMESTAMP:Ljava/lang/String;
-Landroid/os/UpdateLock;->UPDATE_LOCK_CHANGED:Ljava/lang/String;
-Landroid/os/UserHandle;-><init>(I)V
-Landroid/os/UserHandle;->AID_APP_END:I
-Landroid/os/UserHandle;->AID_APP_START:I
-Landroid/os/UserHandle;->AID_CACHE_GID_START:I
-Landroid/os/UserHandle;->AID_ROOT:I
-Landroid/os/UserHandle;->AID_SHARED_GID_START:I
-Landroid/os/UserHandle;->CURRENT_OR_SELF:Landroid/os/UserHandle;
-Landroid/os/UserHandle;->ERR_GID:I
-Landroid/os/UserHandle;->getAppIdFromSharedAppGid(I)I
-Landroid/os/UserHandle;->getCallingUserId()I
-Landroid/os/UserHandle;->getUid(II)I
-Landroid/os/UserHandle;->getUserId(I)I
-Landroid/os/UserHandle;->isIsolated(I)Z
-Landroid/os/UserHandle;->isSameApp(II)Z
-Landroid/os/UserHandle;->mHandle:I
-Landroid/os/UserHandle;->MU_ENABLED:Z
-Landroid/os/UserHandle;->OWNER:Landroid/os/UserHandle;
-Landroid/os/UserHandle;->PER_USER_RANGE:I
-Landroid/os/UserHandle;->USER_ALL:I
-Landroid/os/UserHandle;->USER_CURRENT:I
-Landroid/os/UserHandle;->USER_CURRENT_OR_SELF:I
-Landroid/os/UserHandle;->USER_OWNER:I
-Landroid/os/UserHandle;->USER_SERIAL_SYSTEM:I
-Landroid/os/UserHandle;->USER_SYSTEM:I
-Landroid/os/UserManager;->createProfileForUser(Ljava/lang/String;II)Landroid/content/pm/UserInfo;
-Landroid/os/UserManager;->createUser(Ljava/lang/String;I)Landroid/content/pm/UserInfo;
-Landroid/os/UserManager;->DISALLOW_RECORD_AUDIO:Ljava/lang/String;
-Landroid/os/UserManager;->get(Landroid/content/Context;)Landroid/os/UserManager;
-Landroid/os/UserManager;->getEnabledProfiles(I)Ljava/util/List;
-Landroid/os/UserManager;->getMaxSupportedUsers()I
-Landroid/os/UserManager;->getProfileIdsWithDisabled(I)[I
-Landroid/os/UserManager;->getProfileParent(I)Landroid/content/pm/UserInfo;
-Landroid/os/UserManager;->getProfiles(I)Ljava/util/List;
-Landroid/os/UserManager;->getUserHandle()I
-Landroid/os/UserManager;->getUserHandle(I)I
-Landroid/os/UserManager;->getUserIcon(I)Landroid/graphics/Bitmap;
-Landroid/os/UserManager;->getUserInfo(I)Landroid/content/pm/UserInfo;
-Landroid/os/UserManager;->getUsers()Ljava/util/List;
-Landroid/os/UserManager;->getUsers(Z)Ljava/util/List;
-Landroid/os/UserManager;->getUserSerialNumber(I)I
-Landroid/os/UserManager;->getUserStartRealtime()J
-Landroid/os/UserManager;->getUserUnlockRealtime()J
-Landroid/os/UserManager;->hasBaseUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
-Landroid/os/UserManager;->hasUserRestriction(Ljava/lang/String;Landroid/os/UserHandle;)Z
-Landroid/os/UserManager;->isDeviceInDemoMode(Landroid/content/Context;)Z
-Landroid/os/UserManager;->isGuestUser(I)Z
-Landroid/os/UserManager;->isLinkedUser()Z
-Landroid/os/UserManager;->isUserAdmin(I)Z
-Landroid/os/UserManager;->isUserUnlocked(I)Z
-Landroid/os/UserManager;->mService:Landroid/os/IUserManager;
-Landroid/os/UserManager;->removeUser(I)Z
-Landroid/os/Vibrator;-><init>()V
-Landroid/os/WorkSource;-><init>(Landroid/os/Parcel;)V
-Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
-Landroid/os/WorkSource;->mNum:I
-Landroid/os/WorkSource;->mUids:[I
-Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/String;)V
-Landroid/os/ZygoteStartFailedEx;-><init>(Ljava/lang/Throwable;)V
Landroid/preference/PreferenceGroupAdapter;->getItem(I)Landroid/preference/Preference;
Landroid/R$styleable;->ActionBar:[I
Landroid/R$styleable;->ActionBar_background:I
diff --git a/core/java/android/accessibilityservice/AccessibilityButtonController.java b/core/java/android/accessibilityservice/AccessibilityButtonController.java
index a70085c..af5af9c 100644
--- a/core/java/android/accessibilityservice/AccessibilityButtonController.java
+++ b/core/java/android/accessibilityservice/AccessibilityButtonController.java
@@ -17,7 +17,6 @@
package android.accessibilityservice;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
@@ -76,13 +75,16 @@
* available to the calling service, {@code false} otherwise
*/
public boolean isAccessibilityButtonAvailable() {
- try {
- return mServiceConnection.isAccessibilityButtonAvailable();
- } catch (RemoteException re) {
- Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
- re.rethrowFromSystemServer();
- return false;
+ if (mServiceConnection != null) {
+ try {
+ return mServiceConnection.isAccessibilityButtonAvailable();
+ } catch (RemoteException re) {
+ Slog.w(LOG_TAG, "Failed to get accessibility button availability.", re);
+ re.rethrowFromSystemServer();
+ return false;
+ }
}
+ return false;
}
/**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 664f0a3..e8d3293 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -329,6 +329,9 @@
/** Returns true if the given uid is the app in the foreground. */
public abstract boolean isAppForeground(int uid);
+ /** Returns true if the given uid is currently marked 'bad' */
+ public abstract boolean isAppBad(ApplicationInfo info);
+
/** Remove pending backup for the given userId. */
public abstract void clearPendingBackup(int userId);
@@ -337,4 +340,21 @@
* like persisting database etc.
*/
public abstract void prepareForPossibleShutdown();
+
+ /**
+ * Returns {@code true} if {@code uid} is running a foreground service of a specific
+ * {@code foregroundServiceType}.
+ */
+ public abstract boolean hasRunningForegroundService(int uid, int foregroundServiceType);
+
+ /**
+ * Registers the specified {@code processObserver} to be notified of future changes to
+ * process state.
+ */
+ public abstract void registerProcessObserver(IProcessObserver processObserver);
+
+ /**
+ * Unregisters the specified {@code processObserver}.
+ */
+ public abstract void unregisterProcessObserver(IProcessObserver processObserver);
}
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index e2d868f..da9ea83 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -222,6 +222,13 @@
private static final String KEY_AVOID_MOVE_TO_FRONT = "android.activity.avoidMoveToFront";
/**
+ * See {@link #setFreezeRecentTasksReordering()}.
+ * @hide
+ */
+ private static final String KEY_FREEZE_RECENT_TASKS_REORDERING =
+ "android.activity.freezeRecentTasksReordering";
+
+ /**
* Where the split-screen-primary stack should be positioned.
* @hide
*/
@@ -324,6 +331,7 @@
private boolean mTaskOverlay;
private boolean mTaskOverlayCanResume;
private boolean mAvoidMoveToFront;
+ private boolean mFreezeRecentTasksReordering;
private AppTransitionAnimationSpec mAnimSpecs[];
private int mRotationAnimationHint = -1;
private Bundle mAppVerificationBundle;
@@ -946,6 +954,7 @@
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
+ mFreezeRecentTasksReordering = opts.getBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, false);
mSplitScreenCreateMode = opts.getInt(KEY_SPLIT_SCREEN_CREATE_MODE,
SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT);
mDisallowEnterPictureInPictureWhileLaunching = opts.getBoolean(
@@ -1304,6 +1313,24 @@
return mAvoidMoveToFront;
}
+ /**
+ * Sets whether the launch of this activity should freeze the recent task list reordering until
+ * the next user interaction or timeout. This flag is only applied when starting an activity
+ * in recents.
+ * @hide
+ */
+ public void setFreezeRecentTasksReordering() {
+ mFreezeRecentTasksReordering = true;
+ }
+
+ /**
+ * @return whether the launch of this activity should freeze the recent task list reordering
+ * @hide
+ */
+ public boolean freezeRecentTasksReordering() {
+ return mFreezeRecentTasksReordering;
+ }
+
/** @hide */
public int getSplitScreenCreateMode() {
return mSplitScreenCreateMode;
@@ -1502,6 +1529,9 @@
if (mAvoidMoveToFront) {
b.putBoolean(KEY_AVOID_MOVE_TO_FRONT, mAvoidMoveToFront);
}
+ if (mFreezeRecentTasksReordering) {
+ b.putBoolean(KEY_FREEZE_RECENT_TASKS_REORDERING, mFreezeRecentTasksReordering);
+ }
if (mSplitScreenCreateMode != SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT) {
b.putInt(KEY_SPLIT_SCREEN_CREATE_MODE, mSplitScreenCreateMode);
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 91df05f..5ed4428 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -48,7 +48,6 @@
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-
import com.android.internal.annotations.Immutable;
import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsCallback;
@@ -1098,6 +1097,8 @@
/** @hide Write media of image type. */
public static final String OPSTR_WRITE_MEDIA_IMAGES = "android:write_media_images";
/** @hide Has a legacy (non-isolated) view of storage. */
+ @TestApi
+ @SystemApi
public static final String OPSTR_LEGACY_STORAGE = "android:legacy_storage";
/** @hide Interact with accessibility. */
@SystemApi
@@ -2153,6 +2154,7 @@
*
* @hide
*/
+ @TestApi
@SystemApi
public static int opToDefaultMode(@NonNull String appOp) {
return opToDefaultMode(strOpToOp(appOp));
@@ -2214,7 +2216,7 @@
/**
* @return The ops of the package.
*/
- public List<OpEntry> getOps() {
+ public @NonNull List<OpEntry> getOps() {
return mEntries;
}
@@ -4371,7 +4373,8 @@
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
- public List<PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
+ public @NonNull List<PackageOps> getOpsForPackage(int uid, @NonNull String packageName,
+ @Nullable int[] ops) {
try {
return mService.getOpsForPackage(uid, packageName, ops);
} catch (RemoteException e) {
@@ -4464,7 +4467,7 @@
* @hide
*/
@TestApi
- @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS)
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
public void getHistoricalOpsFromDiskRaw(@NonNull HistoricalOpsRequest request,
@Nullable Executor executor, @NonNull Consumer<HistoricalOps> callback) {
Preconditions.checkNotNull(executor, "executor cannot be null");
@@ -4487,6 +4490,21 @@
}
/**
+ * Reloads the non historical state to allow testing the read/write path.
+ *
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(Manifest.permission.MANAGE_APPOPS)
+ public void reloadNonHistoricalState() {
+ try {
+ mService.reloadNonHistoricalState();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Sets given app op in the specified mode for app ops in the UID.
* This applies to all apps currently in the UID or installed in
* this UID in the future.
@@ -4569,6 +4587,7 @@
* be changed.
* @hide
*/
+ @TestApi
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
public void setMode(String op, int uid, String packageName, @Mode int mode) {
@@ -4639,8 +4658,8 @@
* @param packageName The name of the application to monitor.
* @param callback Where to report changes.
*/
- public void startWatchingMode(String op, String packageName,
- final OnOpChangedListener callback) {
+ public void startWatchingMode(@NonNull String op, @Nullable String packageName,
+ @NonNull final OnOpChangedListener callback) {
startWatchingMode(strOpToOp(op), packageName, callback);
}
@@ -4653,8 +4672,8 @@
* @param flags Option flags: any combination of {@link #WATCH_FOREGROUND_CHANGES} or 0.
* @param callback Where to report changes.
*/
- public void startWatchingMode(String op, String packageName, int flags,
- final OnOpChangedListener callback) {
+ public void startWatchingMode(@NonNull String op, @Nullable String packageName, int flags,
+ @NonNull final OnOpChangedListener callback) {
startWatchingMode(strOpToOp(op), packageName, flags, callback);
}
@@ -4716,7 +4735,7 @@
* Stop monitoring that was previously started with {@link #startWatchingMode}. All
* monitoring associated with this callback will be removed.
*/
- public void stopWatchingMode(OnOpChangedListener callback) {
+ public void stopWatchingMode(@NonNull OnOpChangedListener callback) {
synchronized (mModeWatchers) {
IAppOpsCallback cb = mModeWatchers.remove(callback);
if (cb != null) {
@@ -4875,7 +4894,7 @@
* {@hide}
*/
@TestApi
- public static int strOpToOp(String op) {
+ public static int strOpToOp(@NonNull String op) {
Integer val = sOpStrToOp.get(op);
if (val == null) {
throw new IllegalArgumentException("Unknown operation string: " + op);
@@ -4910,7 +4929,7 @@
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
*/
- public int unsafeCheckOp(String op, int uid, String packageName) {
+ public int unsafeCheckOp(@NonNull String op, int uid, @NonNull String packageName) {
return checkOp(strOpToOp(op), uid, packageName);
}
@@ -4918,7 +4937,7 @@
* @deprecated Renamed to {@link #unsafeCheckOp(String, int, String)}.
*/
@Deprecated
- public int checkOp(String op, int uid, String packageName) {
+ public int checkOp(@NonNull String op, int uid, @NonNull String packageName) {
return checkOp(strOpToOp(op), uid, packageName);
}
@@ -4926,7 +4945,7 @@
* Like {@link #checkOp} but instead of throwing a {@link SecurityException} it
* returns {@link #MODE_ERRORED}.
*/
- public int unsafeCheckOpNoThrow(String op, int uid, String packageName) {
+ public int unsafeCheckOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
@@ -4934,7 +4953,7 @@
* @deprecated Renamed to {@link #unsafeCheckOpNoThrow(String, int, String)}.
*/
@Deprecated
- public int checkOpNoThrow(String op, int uid, String packageName) {
+ public int checkOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return checkOpNoThrow(strOpToOp(op), uid, packageName);
}
@@ -4942,7 +4961,7 @@
* Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
* Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
*/
- public int unsafeCheckOpRaw(@NonNull String op, int uid, String packageName) {
+ public int unsafeCheckOpRaw(@NonNull String op, int uid, @NonNull String packageName) {
try {
return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
} catch (RemoteException e) {
@@ -4977,7 +4996,7 @@
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
*/
- public int noteOp(String op, int uid, String packageName) {
+ public int noteOp(@NonNull String op, int uid, @NonNull String packageName) {
return noteOp(strOpToOp(op), uid, packageName);
}
@@ -4985,7 +5004,7 @@
* Like {@link #noteOp} but instead of throwing a {@link SecurityException} it
* returns {@link #MODE_ERRORED}.
*/
- public int noteOpNoThrow(String op, int uid, String packageName) {
+ public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return noteOpNoThrow(strOpToOp(op), uid, packageName);
}
@@ -5004,7 +5023,7 @@
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
*/
- public int noteProxyOp(String op, String proxiedPackageName) {
+ public int noteProxyOp(@NonNull String op, @NonNull String proxiedPackageName) {
return noteProxyOp(strOpToOp(op), proxiedPackageName);
}
@@ -5015,7 +5034,7 @@
* <p>This API requires the package with the {@code proxiedPackageName} to belongs to
* {@link Binder#getCallingUid()}.
*/
- public int noteProxyOpNoThrow(String op, String proxiedPackageName) {
+ public int noteProxyOpNoThrow(@NonNull String op, @NonNull String proxiedPackageName) {
return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName);
}
@@ -5051,7 +5070,7 @@
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
*/
- public int startOp(String op, int uid, String packageName) {
+ public int startOp(@NonNull String op, int uid, @NonNull String packageName) {
return startOp(strOpToOp(op), uid, packageName);
}
@@ -5059,7 +5078,7 @@
* Like {@link #startOp} but instead of throwing a {@link SecurityException} it
* returns {@link #MODE_ERRORED}.
*/
- public int startOpNoThrow(String op, int uid, String packageName) {
+ public int startOpNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
return startOpNoThrow(strOpToOp(op), uid, packageName);
}
@@ -5069,7 +5088,7 @@
* or result; the parameters supplied here must be the exact same ones previously passed
* in when starting the operation.
*/
- public void finishOp(String op, int uid, String packageName) {
+ public void finishOp(@NonNull String op, int uid, @NonNull String packageName) {
finishOp(strOpToOp(op), uid, packageName);
}
@@ -5135,7 +5154,7 @@
* @throws SecurityException if the package name doesn't belong to the given
* UID, or if ownership cannot be verified.
*/
- public void checkPackage(int uid, String packageName) {
+ public void checkPackage(int uid, @NonNull String packageName) {
try {
if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
throw new SecurityException(
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a226062..7a0639e 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -3054,9 +3054,9 @@
}
@Override
- public String getContentCaptureServicePackageName() {
+ public String getSystemCaptionsServicePackageName() {
try {
- return mPM.getContentCaptureServicePackageName();
+ return mPM.getSystemCaptionsServicePackageName();
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 29e6807..7884872 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -70,6 +70,10 @@
boolean areNotificationsEnabled(String pkg);
int getPackageImportance(String pkg);
+ List<String> getAllowedAssistantCapabilities(String pkg);
+ void allowAssistantCapability(String adjustmentType);
+ void disallowAssistantCapability(String adjustmentType);
+
boolean shouldHideSilentStatusIcons(String callingPkg);
void setHideSilentStatusIcons(boolean hide);
@@ -86,10 +90,10 @@
NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(String pkg, int uid, String groupId, boolean includeDeleted);
void updateNotificationChannelGroupForPackage(String pkg, int uid, in NotificationChannelGroup group);
void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
- NotificationChannel getNotificationChannel(String pkg, String channelId);
+ NotificationChannel getNotificationChannel(String callingPkg, int userId, String pkg, String channelId);
NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
void deleteNotificationChannel(String pkg, String channelId);
- ParceledListSlice getNotificationChannels(String pkg);
+ ParceledListSlice getNotificationChannels(String callingPkg, String targetPkg, int userId);
ParceledListSlice getNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getNumNotificationChannelsForPackage(String pkg, int uid, boolean includeDeleted);
int getDeletedChannelCount(String pkg, int uid);
@@ -193,7 +197,7 @@
void setNotificationDelegate(String callingPkg, String delegate);
String getNotificationDelegate(String callingPkg);
- boolean canNotifyAsPackage(String callingPkg, String targetPkg);
+ boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId);
void setPrivateNotificationsAllowed(boolean allow);
boolean getPrivateNotificationsAllowed();
diff --git a/core/java/android/app/IProcessObserver.aidl b/core/java/android/app/IProcessObserver.aidl
index b436aa2..7be3620 100644
--- a/core/java/android/app/IProcessObserver.aidl
+++ b/core/java/android/app/IProcessObserver.aidl
@@ -19,5 +19,6 @@
/** {@hide} */
oneway interface IProcessObserver {
void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities);
+ void onForegroundServicesChanged(int pid, int uid, int serviceTypes);
void onProcessDied(int pid, int uid);
}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 3ecb587..bcd43a2 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -440,7 +440,7 @@
*/
public boolean isKeyguardSecure() {
try {
- return mWM.isKeyguardSecure();
+ return mWM.isKeyguardSecure(mContext.getUserId());
} catch (RemoteException ex) {
return false;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index db8c905..41a9921 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -781,6 +781,16 @@
isBundledApp = false;
}
+ // Similar to vendor apks, we should add /product/lib for apks from product partition
+ // and not having /product/lib in the default search path
+ final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib");
+ if (mApplicationInfo.getCodePath() != null
+ && mApplicationInfo.isProduct() && treatProductApkAsUnbundled
+ // TODO(b/128557860): Change target SDK version when version code R is available.
+ && getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) {
+ isBundledApp = false;
+ }
+
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
String libraryPermittedPath = mDataDir;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index a8a34d2..523b200 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1203,7 +1203,7 @@
/**
* {@link #extras} key: whether the notification should be colorized as
- * supplied to {@link Builder#setColorized(boolean)}}.
+ * supplied to {@link Builder#setColorized(boolean)}.
*/
public static final String EXTRA_COLORIZED = "android.colorized";
@@ -1358,7 +1358,7 @@
*
* This is intended for {@link RemoteInput}s that only accept data, meaning
* {@link RemoteInput#getAllowFreeFormInput} is false, {@link RemoteInput#getChoices}
- * is null or empty, and {@link RemoteInput#getAllowedDataTypes is non-null and not
+ * is null or empty, and {@link RemoteInput#getAllowedDataTypes} is non-null and not
* empty. These {@link RemoteInput}s will be ignored by devices that do not
* support non-text-based {@link RemoteInput}s. See {@link Builder#build}.
*
@@ -1569,12 +1569,12 @@
* Builder class for {@link Action} objects.
*/
public static final class Builder {
- private final Icon mIcon;
- private final CharSequence mTitle;
- private final PendingIntent mIntent;
+ @Nullable private final Icon mIcon;
+ @Nullable private final CharSequence mTitle;
+ @Nullable private final PendingIntent mIntent;
private boolean mAllowGeneratedReplies = true;
- private final Bundle mExtras;
- private ArrayList<RemoteInput> mRemoteInputs;
+ @NonNull private final Bundle mExtras;
+ @Nullable private ArrayList<RemoteInput> mRemoteInputs;
private @SemanticAction int mSemanticAction;
private boolean mIsContextual;
@@ -1610,9 +1610,10 @@
action.getAllowGeneratedReplies(), action.getSemanticAction());
}
- private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
- RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
- @SemanticAction int semanticAction) {
+ private Builder(@Nullable Icon icon, @Nullable CharSequence title,
+ @Nullable PendingIntent intent, @NonNull Bundle extras,
+ @Nullable RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+ @SemanticAction int semanticAction) {
mIcon = icon;
mTitle = title;
mIntent = intent;
@@ -1645,6 +1646,7 @@
*
* <p>The returned Bundle is shared with this Builder.
*/
+ @NonNull
public Bundle getExtras() {
return mExtras;
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 204fb6a..1aacf96 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -42,6 +42,7 @@
import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.service.notification.Adjustment;
import android.service.notification.Condition;
import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
@@ -627,7 +628,7 @@
public boolean canNotifyAsPackage(@NonNull String pkg) {
INotificationManager service = getService();
try {
- return service.canNotifyAsPackage(mContext.getPackageName(), pkg);
+ return service.canNotifyAsPackage(mContext.getPackageName(), pkg, mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -715,12 +716,16 @@
/**
* Returns the notification channel settings for a given channel id.
*
- * The channel must belong to your package, or it will not be returned.
+ * <p>The channel must belong to your package, or to a package you are an approved notification
+ * delegate for (see {@link #canNotifyAsPackage(String)}), or it will not be returned. To query
+ * a channel as a notification delegate, call this method from a context created for that
+ * package (see {@link Context#createPackageContext(String, int)}).</p>
*/
public NotificationChannel getNotificationChannel(String channelId) {
INotificationManager service = getService();
try {
- return service.getNotificationChannel(mContext.getPackageName(), channelId);
+ return service.getNotificationChannel(mContext.getOpPackageName(),
+ mContext.getUserId(), mContext.getPackageName(), channelId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -728,11 +733,17 @@
/**
* Returns all notification channels belonging to the calling package.
+ *
+ * <p>Approved notification delegates (see {@link #canNotifyAsPackage(String)}) can query
+ * notification channels belonging to packages they are the delegate for. To do so, call this
+ * method from a context created for that package (see
+ * {@link Context#createPackageContext(String, int)}).</p>
*/
public List<NotificationChannel> getNotificationChannels() {
INotificationManager service = getService();
try {
- return service.getNotificationChannels(mContext.getPackageName()).getList();
+ return service.getNotificationChannels(mContext.getOpPackageName(),
+ mContext.getPackageName(), mContext.getUserId()).getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1182,6 +1193,25 @@
}
}
+ /**
+ * Returns the list of {@link android.service.notification.Adjustment adjustment keys} that can
+ * be modified by the current {@link android.service.notification.NotificationAssistantService}.
+ *
+ * <p>Only callable by the current
+ * {@link android.service.notification.NotificationAssistantService}.
+ * See {@link #isNotificationAssistantAccessGranted(ComponentName)}</p>
+ * @hide
+ */
+ @SystemApi
+ public @NonNull @Adjustment.Keys List<String> getAllowedAssistantCapabilities() {
+ INotificationManager service = getService();
+ try {
+ return service.getAllowedAssistantCapabilities(mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
INotificationManager service = getService();
@@ -1270,6 +1300,8 @@
/**
* Grants/revokes Notification Assistant access to {@code assistant} for current user.
+ * To grant access for a particular user, obtain this service by using the {@link Context}
+ * provided by {@link Context#createPackageContextAsUser}
*
* @param assistant Name of component to grant/revoke access or {@code null} to revoke access to
* current assistant
@@ -1287,27 +1319,6 @@
}
}
- /**
- * Grants/revokes Notification Assistant access to {@code assistant} for given user.
- *
- * @param assistant Name of component to grant/revoke access or {@code null} to revoke access to
- * current assistant
- * @param user handle to associate assistant with
- * @param granted Grant/revoke access
- * @hide
- */
- @SystemApi
- public void setNotificationAssistantAccessGrantedForUser(@Nullable ComponentName assistant,
- @NonNull UserHandle user, boolean granted) {
- INotificationManager service = getService();
- try {
- service.setNotificationAssistantAccessGrantedForUser(assistant, user.getIdentifier(),
- granted);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/** @hide */
public List<ComponentName> getEnabledNotificationListeners(int userId) {
INotificationManager service = getService();
@@ -1320,18 +1331,6 @@
/** @hide */
@SystemApi
- public @Nullable ComponentName getAllowedNotificationAssistantForUser(
- @NonNull UserHandle user) {
- INotificationManager service = getService();
- try {
- return service.getAllowedNotificationAssistantForUser(user.getIdentifier());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /** @hide */
- @SystemApi
public @Nullable ComponentName getAllowedNotificationAssistant() {
INotificationManager service = getService();
try {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 08e0880..4d280b7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -101,11 +101,9 @@
import android.net.EthernetManager;
import android.net.IConnectivityManager;
import android.net.IEthernetManager;
-import android.net.IIpMemoryStore;
import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
import android.net.ITestNetworkManager;
-import android.net.IpMemoryStore;
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
@@ -340,17 +338,6 @@
}
});
- registerService(Context.IP_MEMORY_STORE_SERVICE, IpMemoryStore.class,
- new CachedServiceFetcher<IpMemoryStore>() {
- @Override
- public IpMemoryStore createService(final ContextImpl ctx)
- throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(
- Context.IP_MEMORY_STORE_SERVICE);
- IIpMemoryStore service = IIpMemoryStore.Stub.asInterface(b);
- return new IpMemoryStore(ctx, service);
- }});
-
registerService(Context.IPSEC_SERVICE, IpSecManager.class,
new CachedServiceFetcher<IpSecManager>() {
@Override
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9a4e215..20e85e6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -112,6 +112,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -5171,7 +5172,8 @@
* </ul>
* The call will fail if called with the package name of an unsupported VPN app.
* <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure
- * of the VPN provider could break networking for all apps.
+ * of the VPN provider could break networking for all apps. This method clears any lockdown
+ * whitelist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}.
*
* @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to
* remove an existing always-on VPN configuration.
@@ -5181,11 +5183,11 @@
* @throws NameNotFoundException if {@code vpnPackage} is not installed.
* @throws UnsupportedOperationException if {@code vpnPackage} exists but does not support being
* set as always-on, or if always-on VPN is not available.
- * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+ * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
boolean lockdownEnabled) throws NameNotFoundException {
- setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptyList());
+ setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled, Collections.emptySet());
}
/**
@@ -5195,6 +5197,11 @@
* System apps can always bypass VPN.
* <p> Note that the system doesn't update the whitelist when packages are installed or
* uninstalled, the admin app must call this method to keep the list up to date.
+ * <p> When {@code lockdownEnabled} is false {@code lockdownWhitelist} is ignored . When
+ * {@code lockdownEnabled} is {@code true} and {@code lockdownWhitelist} is {@code null} or
+ * empty, only system apps can bypass VPN.
+ * <p> Setting always-on VPN package to {@code null} or using
+ * {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean)} clears lockdown whitelist.
*
* @param vpnPackage package name for an installed VPN app on the device, or {@code null}
* to remove an existing always-on VPN configuration
@@ -5211,13 +5218,13 @@
* available.
*/
public void setAlwaysOnVpnPackage(@NonNull ComponentName admin, @Nullable String vpnPackage,
- boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist)
+ boolean lockdownEnabled, @Nullable Set<String> lockdownWhitelist)
throws NameNotFoundException {
throwIfParentInstance("setAlwaysOnVpnPackage");
if (mService != null) {
try {
- mService.setAlwaysOnVpnPackage(
- admin, vpnPackage, lockdownEnabled, lockdownWhitelist);
+ mService.setAlwaysOnVpnPackage(admin, vpnPackage, lockdownEnabled,
+ lockdownWhitelist == null ? null : new ArrayList<>(lockdownWhitelist));
} catch (ServiceSpecificException e) {
switch (e.errorCode) {
case ERROR_VPN_PACKAGE_NOT_FOUND:
@@ -5255,7 +5262,7 @@
}
/**
- * Called by device or profile owner to query the list of packages that are allowed to access
+ * Called by device or profile owner to query the set of packages that are allowed to access
* the network directly when always-on VPN is in lockdown mode but not connected. Returns
* {@code null} when always-on VPN is not active or not in lockdown mode.
*
@@ -5263,13 +5270,15 @@
*
* @throws SecurityException if {@code admin} is not a device or a profile owner.
*
- * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, List)
+ * @see #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
- public @Nullable List<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
+ public @Nullable Set<String> getAlwaysOnVpnLockdownWhitelist(@NonNull ComponentName admin) {
throwIfParentInstance("getAlwaysOnVpnLockdownWhitelist");
if (mService != null) {
try {
- return mService.getAlwaysOnVpnLockdownWhitelist(admin);
+ final List<String> whitelist =
+ mService.getAlwaysOnVpnLockdownWhitelist(admin);
+ return whitelist == null ? null : new HashSet<>(whitelist);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6339,7 +6348,6 @@
*/
@RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS,
conditional = true)
- @SystemApi
public @Nullable ComponentName getProfileOwnerAsUser(@NonNull UserHandle user) {
if (mService != null) {
try {
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index bcc4974..25caaaa 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -502,32 +503,76 @@
* @param transportComponent The identity of the transport being described.
* @param name A {@link String} with the new name for the transport. This is NOT for
* identification. MUST NOT be {@code null}.
- * @param configurationIntent An {@link Intent} that can be passed to
- * {@link Context#startActivity} in order to launch the transport's configuration UI. It may
- * be {@code null} if the transport does not offer any user-facing configuration UI.
+ * @param configurationIntent An {@link Intent} that can be passed to {@link
+ * Context#startActivity} in order to launch the transport's configuration UI. It may be
+ * {@code null} if the transport does not offer any user-facing configuration UI.
* @param currentDestinationString A {@link String} describing the destination to which the
* transport is currently sending data. MUST NOT be {@code null}.
- * @param dataManagementIntent An {@link Intent} that can be passed to
- * {@link Context#startActivity} in order to launch the transport's data-management UI. It
- * may be {@code null} if the transport does not offer any user-facing data
- * management UI.
+ * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+ * Context#startActivity} in order to launch the transport's data-management UI. It may be
+ * {@code null} if the transport does not offer any user-facing data management UI.
* @param dataManagementLabel A {@link String} to be used as the label for the transport's data
- * management affordance. This MUST be {@code null} when dataManagementIntent is
- * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+ * null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
+ * @deprecated Since Android Q, please use the variant {@link
+ * #updateTransportAttributes(ComponentName, String, Intent, String, Intent, CharSequence)}
+ * instead.
+ * @hide
+ */
+ @Deprecated
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ public void updateTransportAttributes(
+ @NonNull ComponentName transportComponent,
+ @NonNull String name,
+ @Nullable Intent configurationIntent,
+ @NonNull String currentDestinationString,
+ @Nullable Intent dataManagementIntent,
+ @Nullable String dataManagementLabel) {
+ updateTransportAttributes(
+ transportComponent,
+ name,
+ configurationIntent,
+ currentDestinationString,
+ dataManagementIntent,
+ (CharSequence) dataManagementLabel);
+ }
+
+ /**
+ * Update the attributes of the transport identified by {@code transportComponent}. If the
+ * specified transport has not been bound at least once (for registration), this call will be
+ * ignored. Only the host process of the transport can change its description, otherwise a
+ * {@link SecurityException} will be thrown.
*
+ * @param transportComponent The identity of the transport being described.
+ * @param name A {@link String} with the new name for the transport. This is NOT for
+ * identification. MUST NOT be {@code null}.
+ * @param configurationIntent An {@link Intent} that can be passed to {@link
+ * Context#startActivity} in order to launch the transport's configuration UI. It may be
+ * {@code null} if the transport does not offer any user-facing configuration UI.
+ * @param currentDestinationString A {@link String} describing the destination to which the
+ * transport is currently sending data. MUST NOT be {@code null}.
+ * @param dataManagementIntent An {@link Intent} that can be passed to {@link
+ * Context#startActivity} in order to launch the transport's data-management UI. It may be
+ * {@code null} if the transport does not offer any user-facing data management UI.
+ * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+ * data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+ * null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * @throws SecurityException If the UID of the calling process differs from the package UID of
+ * {@code transportComponent} or if the caller does NOT have BACKUP permission.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.BACKUP)
public void updateTransportAttributes(
- ComponentName transportComponent,
- String name,
+ @NonNull ComponentName transportComponent,
+ @NonNull String name,
@Nullable Intent configurationIntent,
- String currentDestinationString,
+ @NonNull String currentDestinationString,
@Nullable Intent dataManagementIntent,
- @Nullable String dataManagementLabel) {
+ @Nullable CharSequence dataManagementLabel) {
checkServiceBinder();
if (sService != null) {
try {
@@ -796,7 +841,7 @@
/**
* Returns an {@link Intent} for the specified transport's configuration UI.
* This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
- * Intent, String)}.
+ * Intent, CharSequence)}.
* @param transportName The name of the registered transport.
* @hide
*/
@@ -818,7 +863,7 @@
/**
* Returns a {@link String} describing where the specified transport is sending data.
* This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
- * Intent, String)}.
+ * Intent, CharSequence)}.
* @param transportName The name of the registered transport.
* @hide
*/
@@ -840,7 +885,7 @@
/**
* Returns an {@link Intent} for the specified transport's data management UI.
* This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
- * Intent, String)}.
+ * Intent, CharSequence)}.
* @param transportName The name of the registered transport.
* @hide
*/
@@ -861,9 +906,28 @@
/**
* Returns a {@link String} describing what the specified transport's data management intent is
- * used for.
- * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
- * Intent, String)}.
+ * used for. This value is set by {@link #updateTransportAttributes(ComponentName, String,
+ * Intent, String, Intent, CharSequence)}.
+ *
+ * @param transportName The name of the registered transport.
+ * @deprecated Since Android Q, please use the variant {@link
+ * #getDataManagementIntentLabel(String)} instead.
+ * @hide
+ */
+ @Deprecated
+ @SystemApi
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ @Nullable
+ public String getDataManagementLabel(@NonNull String transportName) {
+ CharSequence label = getDataManagementIntentLabel(transportName);
+ return label == null ? null : label.toString();
+ }
+
+ /**
+ * Returns a {@link CharSequence} describing what the specified transport's data management
+ * intent is used for. This value is set by {@link #updateTransportAttributes(ComponentName,
+ * String, Intent, String, Intent, CharSequence)}.
*
* @param transportName The name of the registered transport.
* @hide
@@ -871,13 +935,14 @@
@SystemApi
@TestApi
@RequiresPermission(android.Manifest.permission.BACKUP)
- public String getDataManagementLabel(String transportName) {
+ @Nullable
+ public CharSequence getDataManagementIntentLabel(@NonNull String transportName) {
checkServiceBinder();
if (sService != null) {
try {
return sService.getDataManagementLabelForUser(mContext.getUserId(), transportName);
} catch (RemoteException e) {
- Log.e(TAG, "getDataManagementLabel() couldn't connect");
+ Log.e(TAG, "getDataManagementIntentLabel() couldn't connect");
}
}
return null;
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index 0963594..c8f2ff3 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -16,6 +16,7 @@
package android.app.backup;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -164,19 +165,36 @@
}
/**
- * On demand, supply a short string that can be shown to the user as the label
- * on an overflow menu item used to invoked the data management UI.
+ * On demand, supply a short string that can be shown to the user as the label on an overflow
+ * menu item used to invoke the data management UI.
*
- * @return A string to be used as the label for the transport's data management
- * affordance. If the transport supplies a data management intent, this
- * method must not return {@code null}.
+ * @return A string to be used as the label for the transport's data management affordance. If
+ * the transport supplies a data management intent, this method must not return {@code
+ * null}.
+ * @deprecated Since Android Q, please use the variant {@link #dataManagementIntentLabel()}
+ * instead.
*/
+ @Deprecated
+ @Nullable
public String dataManagementLabel() {
throw new UnsupportedOperationException(
"Transport dataManagementLabel() not implemented");
}
/**
+ * On demand, supply a short CharSequence that can be shown to the user as the label on an
+ * overflow menu item used to invoke the data management UI.
+ *
+ * @return A CharSequence to be used as the label for the transport's data management
+ * affordance. If the transport supplies a data management intent, this method must not
+ * return {@code null}.
+ */
+ @Nullable
+ public CharSequence dataManagementIntentLabel() {
+ return dataManagementLabel();
+ }
+
+ /**
* Ask the transport where, on local device storage, to keep backup state blobs.
* This is per-transport so that mock transports used for testing can coexist with
* "live" backup services without interfering with the live bookkeeping. The
@@ -651,8 +669,8 @@
}
@Override
- public String dataManagementLabel() {
- return BackupTransport.this.dataManagementLabel();
+ public CharSequence dataManagementIntentLabel() {
+ return BackupTransport.this.dataManagementIntentLabel();
}
@Override
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 70ecdae..2dfaad7 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -353,16 +353,16 @@
* {@link Context#startActivity} in order to launch the transport's data-management UI. It
* may be {@code null} if the transport does not offer any user-facing data
* management UI.
- * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
- * management affordance. This MUST be {@code null} when dataManagementIntent is
- * {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
+ * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+ * data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+ * null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
*/
void updateTransportAttributesForUser(int userId, in ComponentName transportComponent,
in String name,
in Intent configurationIntent, in String currentDestinationString,
- in Intent dataManagementIntent, in String dataManagementLabel);
+ in Intent dataManagementIntent, in CharSequence dataManagementLabel);
/**
* Identify the currently selected transport. Callers must hold the
@@ -525,13 +525,7 @@
*
* @param userId User id for which the manage-data menu label should be reported.
*/
- String getDataManagementLabelForUser(int userId, String transport);
-
- /**
- * {@link android.app.backup.IBackupManager.getDataManagementLabelForUser} for the calling user
- * id.
- */
- String getDataManagementLabel(String transport);
+ CharSequence getDataManagementLabelForUser(int userId, String transport);
/**
* Begin a restore session. Either or both of packageName and transportID
diff --git a/core/java/android/app/backup/IRestoreSession.aidl b/core/java/android/app/backup/IRestoreSession.aidl
index b9e9485..c3a298b 100644
--- a/core/java/android/app/backup/IRestoreSession.aidl
+++ b/core/java/android/app/backup/IRestoreSession.aidl
@@ -71,8 +71,8 @@
* applications mentioned in this list will have their data restored.
* @param monitor If non null the binder will send important events to this monitor.
*/
- int restoreSome(long token, IRestoreObserver observer, IBackupManagerMonitor monitor,
- in String[] packages);
+ int restorePackages(long token, IRestoreObserver observer, in String[] packages,
+ IBackupManagerMonitor monitor);
/**
* Restore a single application from backup. The data will be restored from the
diff --git a/core/java/android/app/backup/RestoreSession.java b/core/java/android/app/backup/RestoreSession.java
index 79925ec..084b13b 100644
--- a/core/java/android/app/backup/RestoreSession.java
+++ b/core/java/android/app/backup/RestoreSession.java
@@ -16,6 +16,8 @@
package android.app.backup;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Bundle;
@@ -24,6 +26,10 @@
import android.os.RemoteException;
import android.util.Log;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Interface for managing a restore session.
* @hide
@@ -138,14 +144,15 @@
* the restore set that should be used.
* @param observer If non-null, this binder points to an object that will receive
* progress callbacks during the restore operation.
- * @param monitor If non-null, this binder points to an object that will receive
- * progress callbacks during the restore operation.
* @param packages The set of packages for which to attempt a restore. Regardless of
* the contents of the actual back-end dataset named by {@code token}, only
* applications mentioned in this list will have their data restored.
+ * @param monitor If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation containing detailed information on any
+ * failures or important decisions made by {@link BackupManager}.
*/
- public int restoreSome(long token, RestoreObserver observer, BackupManagerMonitor monitor,
- String[] packages) {
+ public int restorePackages(long token, @Nullable RestoreObserver observer,
+ @NonNull Set<String> packages, @Nullable BackupManagerMonitor monitor) {
int err = -1;
if (mObserver != null) {
Log.d(TAG, "restoreAll() called during active restore");
@@ -156,7 +163,8 @@
? null
: new BackupManagerMonitorWrapper(monitor);
try {
- err = mBinder.restoreSome(token, mObserver, monitorWrapper, packages);
+ err = mBinder.restorePackages(token, mObserver, packages.toArray(new String[] {}),
+ monitorWrapper);
} catch (RemoteException e) {
Log.d(TAG, "Can't contact server to restore packages");
}
@@ -180,6 +188,60 @@
* the contents of the actual back-end dataset named by {@code token}, only
* applications mentioned in this list will have their data restored.
*/
+ public int restorePackages(long token, @Nullable RestoreObserver observer,
+ @NonNull Set<String> packages) {
+ return restorePackages(token, observer, packages, null);
+ }
+
+ /**
+ * Restore select packages from the given set onto the device, replacing the
+ * current data of any app contained in the set with the data previously
+ * backed up.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @return Zero on success, nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
+ * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+ * the restore set that should be used.
+ * @param observer If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param monitor If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param packages The set of packages for which to attempt a restore. Regardless of
+ * the contents of the actual back-end dataset named by {@code token}, only
+ * applications mentioned in this list will have their data restored.
+ *
+ * @deprecated use {@link RestoreSession#restorePackages(long, RestoreObserver,
+ * BackupManagerMonitor, Set)} instead.
+ */
+ @Deprecated
+ public int restoreSome(long token, RestoreObserver observer, BackupManagerMonitor monitor,
+ String[] packages) {
+ return restorePackages(token, observer, new HashSet<>(Arrays.asList(packages)), monitor);
+ }
+
+ /**
+ * Restore select packages from the given set onto the device, replacing the
+ * current data of any app contained in the set with the data previously
+ * backed up.
+ *
+ * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+ *
+ * @return Zero on success, nonzero on error. The observer will only receive
+ * progress callbacks if this method returned zero.
+ * @param token The token from {@link getAvailableRestoreSets()} corresponding to
+ * the restore set that should be used.
+ * @param observer If non-null, this binder points to an object that will receive
+ * progress callbacks during the restore operation.
+ * @param packages The set of packages for which to attempt a restore. Regardless of
+ * the contents of the actual back-end dataset named by {@code token}, only
+ * applications mentioned in this list will have their data restored.
+ *
+ * @deprecated use {@link RestoreSession#restorePackages(long, RestoreObserver, Set)}
+ * instead.
+ */
+ @Deprecated
public int restoreSome(long token, RestoreObserver observer, String[] packages) {
return restoreSome(token, observer, null, packages);
}
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index b6f37f6..298b003 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -26,7 +26,8 @@
import android.os.Parcelable;
/**
- * TODO(b/111701043): Add java docs
+ * Class that provides contextual information about the environment in which the app prediction is
+ * used, such as package name, UI in which the app targets are shown, and number of targets.
*
* @hide
*/
@@ -57,20 +58,32 @@
mExtras = parcel.readBundle();
}
+ /**
+ * Returns the UI surface of the prediction context.
+ */
@NonNull
public String getUiSurface() {
return mUiSurface;
}
+ /**
+ * Returns the predicted target count
+ */
public @IntRange(from = 0) int getPredictedTargetCount() {
return mPredictedTargetCount;
}
+ /**
+ * Returns the package name of the prediction context.
+ */
@NonNull
public String getPackageName() {
return mPackageName;
}
+ /**
+ * Returns the extras of the prediction context.
+ */
@Nullable
public Bundle getExtras() {
return mExtras;
@@ -100,9 +113,6 @@
dest.writeBundle(mExtras);
}
- /**
- * @see Parcelable.Creator
- */
public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionContext> CREATOR =
new Parcelable.Creator<AppPredictionContext>() {
public AppPredictionContext createFromParcel(Parcel parcel) {
@@ -132,7 +142,7 @@
private Bundle mExtras;
/**
- * TODO(b/123591863): Add java docs
+ * @param context The {@link Context} of the prediction client.
*
* @hide
*/
diff --git a/core/java/android/app/prediction/AppPredictionManager.java b/core/java/android/app/prediction/AppPredictionManager.java
index 45825cf..cb5b7e7 100644
--- a/core/java/android/app/prediction/AppPredictionManager.java
+++ b/core/java/android/app/prediction/AppPredictionManager.java
@@ -23,7 +23,8 @@
import com.android.internal.util.Preconditions;
/**
- * TODO (b/111701043) : Add java doc
+ * Class that provides methods to create prediction clients.
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/prediction/AppPredictionSessionId.java b/core/java/android/app/prediction/AppPredictionSessionId.java
index 1c5d8b4..281a16f 100644
--- a/core/java/android/app/prediction/AppPredictionSessionId.java
+++ b/core/java/android/app/prediction/AppPredictionSessionId.java
@@ -22,7 +22,7 @@
import android.os.Parcelable;
/**
- * TODO (b/111701043) : Add java doc
+ * The id for an app prediction session. See {@link AppPredictor}.
*
* @hide
*/
@@ -33,6 +33,8 @@
private final String mId;
/**
+ * Creates a new id for a prediction session.
+ *
* @hide
*/
public AppPredictionSessionId(@NonNull String id) {
@@ -58,7 +60,6 @@
@Override
public int hashCode() {
- // Ensure that the id has a consistent hash
return mId.hashCode();
}
@@ -72,9 +73,6 @@
dest.writeString(mId);
}
- /**
- * @see Parcelable.Creator
- */
public static final @android.annotation.NonNull Parcelable.Creator<AppPredictionSessionId> CREATOR =
new Parcelable.Creator<AppPredictionSessionId>() {
public AppPredictionSessionId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 284327d..3e4e8dc 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -39,7 +39,7 @@
import java.util.function.Consumer;
/**
- * TODO (b/111701043) : Add java doc
+ * Class that represents an App Prediction client.
*
* <p>
* Usage: <pre> {@code
@@ -49,14 +49,20 @@
*
* void onCreate() {
* mClient = new AppPredictor(...)
+ * mClient.registerPredictionUpdates(...)
* }
*
* void onStart() {
- * mClient.requestPredictionUpdate();
+ * mClient.requestPredictionUpdate()
+ * }
+ *
+ * void onClick(...) {
+ * mClient.notifyAppTargetEvent(...)
* }
*
* void onDestroy() {
- * mClient.close();
+ * mClient.unregisterPredictionUpdates()
+ * mClient.close()
* }
*
* }</pre>
@@ -83,7 +89,8 @@
* The caller should call {@link AppPredictor#destroy()} to dispose the client once it
* no longer used.
*
- * @param predictionContext The prediction context
+ * @param context The {@link Context} of the user of this {@link AppPredictor}.
+ * @param predictionContext The prediction context.
*/
AppPredictor(@NonNull Context context, @NonNull AppPredictionContext predictionContext) {
IBinder b = ServiceManager.getService(Context.APP_PREDICTION_SERVICE);
@@ -102,6 +109,8 @@
/**
* Notifies the prediction service of an app target event.
+ *
+ * @param event The {@link AppTargetEvent} that represents the app target event.
*/
public void notifyAppTargetEvent(@NonNull AppTargetEvent event) {
if (mIsClosed.get()) {
@@ -118,6 +127,9 @@
/**
* Notifies the prediction service when the targets in a launch location are shown to the user.
+ *
+ * @param launchLocation The launch location where the targets are shown to the user.
+ * @param targetIds List of {@link AppTargetId}s that are shown to the user.
*/
public void notifyLocationShown(@NonNull String launchLocation,
@NonNull List<AppTargetId> targetIds) {
@@ -138,7 +150,10 @@
* Requests the prediction service provide continuous updates of App predictions via the
* provided callback, until the given callback is unregistered.
*
- * @see Callback#onTargetsAvailable(List)
+ * @see Callback#onTargetsAvailable(List).
+ *
+ * @param callbackExecutor The callback executor to use when calling the callback.
+ * @param callback The Callback to be called when updates of App predictions are available.
*/
public void registerPredictionUpdates(@NonNull @CallbackExecutor Executor callbackExecutor,
@NonNull AppPredictor.Callback callback) {
@@ -164,6 +179,10 @@
/**
* Requests the prediction service to stop providing continuous updates to the provided
* callback until the callback is re-registered.
+ *
+ * @see {@link AppPredictor#registerPredictionUpdates(Executor, Callback)}.
+ *
+ * @param callback The callback to be unregistered.
*/
public void unregisterPredictionUpdates(@NonNull AppPredictor.Callback callback) {
if (mIsClosed.get()) {
@@ -187,7 +206,7 @@
* Requests the prediction service to dispatch a new set of App predictions via the provided
* callback.
*
- * @see Callback#onTargetsAvailable(List)
+ * @see Callback#onTargetsAvailable(List).
*/
public void requestPredictionUpdate() {
if (mIsClosed.get()) {
@@ -205,6 +224,10 @@
/**
* Returns a new list of AppTargets sorted based on prediction rank or {@code null} if the
* ranker is not available.
+ *
+ * @param targets List of app targets to be sorted.
+ * @param callbackExecutor The callback executor to use when calling the callback.
+ * @param callback The callback to return the sorted list of app targets.
*/
@Nullable
public void sortTargets(@NonNull List<AppTarget> targets,
@@ -255,7 +278,7 @@
}
/**
- * TODO(b/123591863): Add java docs
+ * Returns the id of this prediction session.
*
* @hide
*/
@@ -271,7 +294,7 @@
/**
* Called when a new set of predicted app targets are available.
- * @param targets Sorted list of predicted targets
+ * @param targets Sorted list of predicted targets.
*/
void onTargetsAvailable(@NonNull List<AppTarget> targets);
}
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 6f09d34..bb1b96c 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -29,6 +29,7 @@
/**
* A representation of a launchable target.
+ *
* @hide
*/
@SystemApi
@@ -45,7 +46,12 @@
private int mRank;
/**
- * TODO(b/123591863): Add java docs
+ * Creates an instance of AppTarget that represent a launchable component.
+ *
+ * @param id A unique id for this launchable target.
+ * @param packageName Package name of the target.
+ * @param className Class name of the target.
+ * @param user The UserHandle of the user which this target belongs to.
*
* @hide
*/
@@ -62,7 +68,11 @@
}
/**
- * TODO(b/123591863): Add java docs
+ * Creates an instance of AppTarget that represent a launchable shortcut.
+ *
+ * @param id A unique id for this launchable target.
+ * @param shortcutInfo The {@link ShortcutInfo} that is represented with this target.
+ * @param className Class name fo the target.
*
* @hide
*/
@@ -186,9 +196,6 @@
dest.writeInt(mRank);
}
- /**
- * @see Parcelable.Creator
- */
public static final @android.annotation.NonNull Parcelable.Creator<AppTarget> CREATOR =
new Parcelable.Creator<AppTarget>() {
public AppTarget createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/prediction/AppTargetEvent.java b/core/java/android/app/prediction/AppTargetEvent.java
index f6964f3..54b9563 100644
--- a/core/java/android/app/prediction/AppTargetEvent.java
+++ b/core/java/android/app/prediction/AppTargetEvent.java
@@ -28,6 +28,7 @@
/**
* A representation of an app target event.
+ *
* @hide
*/
@SystemApi
@@ -118,9 +119,6 @@
dest.writeInt(mAction);
}
- /**
- * @see Creator
- */
public static final @android.annotation.NonNull Creator<AppTargetEvent> CREATOR =
new Creator<AppTargetEvent>() {
public AppTargetEvent createFromParcel(Parcel parcel) {
@@ -134,6 +132,7 @@
/**
* A builder for app target events.
+ *
* @hide
*/
@SystemApi
@@ -143,6 +142,10 @@
private String mLocation;
private @ActionType int mAction;
+ /**
+ * @param target The app target that is associated with this event.
+ * @param actionType The event type, which is one of the values in {@link ActionType}.
+ */
public Builder(@Nullable AppTarget target, @ActionType int actionType) {
mTarget = target;
mAction = actionType;
diff --git a/core/java/android/app/prediction/AppTargetId.java b/core/java/android/app/prediction/AppTargetId.java
index aa2ec1f..3603f5f 100644
--- a/core/java/android/app/prediction/AppTargetId.java
+++ b/core/java/android/app/prediction/AppTargetId.java
@@ -22,7 +22,8 @@
import android.os.Parcelable;
/**
- * The id for a prediction target.
+ * The id for a prediction target. See {@link AppTarget}.
+ *
* @hide
*/
@SystemApi
@@ -33,7 +34,7 @@
private final String mId;
/**
- * TODO(b/123591863): Add java docs
+ * Creates a new id for a prediction target.
*
* @hide
*/
@@ -49,6 +50,7 @@
/**
* Returns the id.
+ *
* @hide
*/
@NonNull
@@ -66,7 +68,6 @@
@Override
public int hashCode() {
- // Ensure that the id has a consistent hash
return mId.hashCode();
}
@@ -80,9 +81,6 @@
dest.writeString(mId);
}
- /**
- * @see Creator
- */
public static final @android.annotation.NonNull Creator<AppTargetId> CREATOR =
new Creator<AppTargetId>() {
public AppTargetId createFromParcel(Parcel parcel) {
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index b5224c7..a6ceeb1 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -665,7 +665,6 @@
* @deprecated use {@link #registerUsageSessionObserver(int, String[], Duration, Duration,
* PendingIntent, PendingIntent)}.
*
- * @removed
* @hide
*/
@Deprecated
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index b4eaab2..d6edb90 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -22,7 +22,6 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -92,7 +91,6 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
public static final String ACTION_ACTIVE_DEVICE_CHANGED =
"android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
@@ -324,7 +322,8 @@
/**
* {@inheritDoc}
*/
- @Override public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ @Override
+ public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
@NonNull int[] states) {
if (VDBG) log("getDevicesMatchingStates()");
try {
@@ -346,7 +345,8 @@
* {@inheritDoc}
*/
@Override
- public int getConnectionState(@NonNull BluetoothDevice device) {
+ public @BluetoothProfile.BtProfileState int getConnectionState(
+ @NonNull BluetoothDevice device) {
if (VDBG) log("getState(" + device + ")");
try {
mServiceLock.readLock().lock();
@@ -386,7 +386,6 @@
* @return false on immediate error, true otherwise
* @hide
*/
- @UnsupportedAppUsage
public boolean setActiveDevice(@Nullable BluetoothDevice device) {
if (DBG) log("setActiveDevice(" + device + ")");
try {
@@ -418,7 +417,6 @@
* @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- @UnsupportedAppUsage
public List<BluetoothDevice> getActiveDevices() {
if (VDBG) log("getActiveDevices()");
try {
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index ef77596..dabe0fd 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -276,7 +276,7 @@
* #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public int getConnectionState(BluetoothDevice device);
+ @BtProfileState int getConnectionState(BluetoothDevice device);
/**
* An interface for notifying BluetoothProfile IPC clients when they have
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index efb3bfc1..fb933b1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -338,6 +338,16 @@
public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100;
/**
+ * Flag for {@link #bindService}: This flag is intended to be used only by the system to adjust
+ * the scheduling policy for IMEs (and any other out-of-process user-visible components that
+ * work closely with the top app) so that UI hosted in such services can have the same
+ * scheduling policy (e.g. SCHED_FIFO when it is enabled and TOP_APP_PRIORITY_BOOST otherwise)
+ * as the actual top-app.
+ * @hide
+ */
+ public static final int BIND_SCHEDULE_LIKE_TOP_APP = 0x00080000;
+
+ /**
* Flag for {@link #bindService}: allow background activity starts from the bound service's
* process.
* This flag is only respected if the caller is holding
@@ -3693,14 +3703,6 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.net.IpMemoryStore} to store and read information about
- * known networks.
- * @hide
- */
- public static final String IP_MEMORY_STORE_SERVICE = "ipmemorystore";
-
- /**
- * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
*
@@ -4006,6 +4008,16 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link com.android.server.attention.AttentionManagerService} for attention services.
+ *
+ * @see #getSystemService(String)
+ * @see android.server.attention.AttentionManagerService
+ * @hide
+ */
+ public static final String ATTENTION_SERVICE = "attention";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.view.inputmethod.InputMethodManager} for accessing input
* methods.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a2d3f6a..93a9dac 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1997,7 +1997,8 @@
public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS";
/**
- * Intent extra: ID of the shortcut used to send the share intent.
+ * Intent extra: ID of the shortcut used to send the share intent. Will be sent with
+ * {@link #ACTION_SEND}.
*
* @see ShortcutInfo#getId()
*
@@ -2437,7 +2438,7 @@
* Broadcast Action: A rollback has been committed.
*
* <p class="note">This is a protected intent that can only be sent
- * by the system.
+ * by the system. The receiver must hold MANAGE_ROLLBACK permission.
*
* @hide
*/
diff --git a/core/java/android/content/LoggingContentInterface.java b/core/java/android/content/LoggingContentInterface.java
index 26d01b9..6e12a57 100644
--- a/core/java/android/content/LoggingContentInterface.java
+++ b/core/java/android/content/LoggingContentInterface.java
@@ -66,7 +66,12 @@
} else {
sb.append(" = ").append(deepToString(res));
}
- Log.v(tag, sb.toString());
+
+ if (res instanceof Exception) {
+ Log.e(tag, sb.toString());
+ } else {
+ Log.v(tag, sb.toString());
+ }
}
private String deepToString(Object value) {
@@ -81,119 +86,194 @@
public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal)
throws RemoteException {
- final Cursor res = delegate.query(uri, projection, queryArgs, cancellationSignal);
- log("query", res, uri, projection, queryArgs, cancellationSignal);
- return res;
+ try {
+ final Cursor res = delegate.query(uri, projection, queryArgs, cancellationSignal);
+ log("query", res, uri, projection, queryArgs, cancellationSignal);
+ return res;
+ } catch (Exception res) {
+ log("query", res, uri, projection, queryArgs, cancellationSignal);
+ throw res;
+ }
}
@Override
public @Nullable String getType(@NonNull Uri uri) throws RemoteException {
- final String res = delegate.getType(uri);
- log("getType", res, uri);
- return res;
+ try {
+ final String res = delegate.getType(uri);
+ log("getType", res, uri);
+ return res;
+ } catch (Exception res) {
+ log("getType", res, uri);
+ throw res;
+ }
}
@Override
public @Nullable String[] getStreamTypes(@NonNull Uri uri, @NonNull String mimeTypeFilter)
throws RemoteException {
- final String[] res = delegate.getStreamTypes(uri, mimeTypeFilter);
- log("getStreamTypes", res, uri, mimeTypeFilter);
- return res;
+ try {
+ final String[] res = delegate.getStreamTypes(uri, mimeTypeFilter);
+ log("getStreamTypes", res, uri, mimeTypeFilter);
+ return res;
+ } catch (Exception res) {
+ log("getStreamTypes", res, uri, mimeTypeFilter);
+ throw res;
+ }
}
@Override
public @Nullable Uri canonicalize(@NonNull Uri uri) throws RemoteException {
- final Uri res = delegate.canonicalize(uri);
- log("canonicalize", res, uri);
- return res;
+ try {
+ final Uri res = delegate.canonicalize(uri);
+ log("canonicalize", res, uri);
+ return res;
+ } catch (Exception res) {
+ log("canonicalize", res, uri);
+ throw res;
+ }
}
@Override
public @Nullable Uri uncanonicalize(@NonNull Uri uri) throws RemoteException {
- final Uri res = delegate.uncanonicalize(uri);
- log("uncanonicalize", res, uri);
- return res;
+ try {
+ final Uri res = delegate.uncanonicalize(uri);
+ log("uncanonicalize", res, uri);
+ return res;
+ } catch (Exception res) {
+ log("uncanonicalize", res, uri);
+ throw res;
+ }
}
@Override
public boolean refresh(@NonNull Uri uri, @Nullable Bundle args,
@Nullable CancellationSignal cancellationSignal) throws RemoteException {
- final boolean res = delegate.refresh(uri, args, cancellationSignal);
- log("refresh", res, uri, args, cancellationSignal);
- return res;
+ try {
+ final boolean res = delegate.refresh(uri, args, cancellationSignal);
+ log("refresh", res, uri, args, cancellationSignal);
+ return res;
+ } catch (Exception res) {
+ log("refresh", res, uri, args, cancellationSignal);
+ throw res;
+ }
}
@Override
public @Nullable Uri insert(@NonNull Uri uri, @Nullable ContentValues initialValues)
throws RemoteException {
- final Uri res = delegate.insert(uri, initialValues);
- log("insert", res, uri, initialValues);
- return res;
+ try {
+ final Uri res = delegate.insert(uri, initialValues);
+ log("insert", res, uri, initialValues);
+ return res;
+ } catch (Exception res) {
+ log("insert", res, uri, initialValues);
+ throw res;
+ }
}
@Override
public int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] initialValues)
throws RemoteException {
- final int res = delegate.bulkInsert(uri, initialValues);
- log("bulkInsert", res, uri, initialValues);
- return res;
+ try {
+ final int res = delegate.bulkInsert(uri, initialValues);
+ log("bulkInsert", res, uri, initialValues);
+ return res;
+ } catch (Exception res) {
+ log("bulkInsert", res, uri, initialValues);
+ throw res;
+ }
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection,
@Nullable String[] selectionArgs) throws RemoteException {
- final int res = delegate.delete(uri, selection, selectionArgs);
- log("delete", res, uri, selection, selectionArgs);
- return res;
+ try {
+ final int res = delegate.delete(uri, selection, selectionArgs);
+ log("delete", res, uri, selection, selectionArgs);
+ return res;
+ } catch (Exception res) {
+ log("delete", res, uri, selection, selectionArgs);
+ throw res;
+ }
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
@Nullable String[] selectionArgs) throws RemoteException {
- final int res = delegate.update(uri, values, selection, selectionArgs);
- log("update", res, uri, values, selection, selectionArgs);
- return res;
+ try {
+ final int res = delegate.update(uri, values, selection, selectionArgs);
+ log("update", res, uri, values, selection, selectionArgs);
+ return res;
+ } catch (Exception res) {
+ log("update", res, uri, values, selection, selectionArgs);
+ throw res;
+ }
}
@Override
public @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
@Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
- final ParcelFileDescriptor res = delegate.openFile(uri, mode, signal);
- log("openFile", res, uri, mode, signal);
- return res;
+ try {
+ final ParcelFileDescriptor res = delegate.openFile(uri, mode, signal);
+ log("openFile", res, uri, mode, signal);
+ return res;
+ } catch (Exception res) {
+ log("openFile", res, uri, mode, signal);
+ throw res;
+ }
}
@Override
public @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
@Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
- final AssetFileDescriptor res = delegate.openAssetFile(uri, mode, signal);
- log("openAssetFile", res, uri, mode, signal);
- return res;
+ try {
+ final AssetFileDescriptor res = delegate.openAssetFile(uri, mode, signal);
+ log("openAssetFile", res, uri, mode, signal);
+ return res;
+ } catch (Exception res) {
+ log("openAssetFile", res, uri, mode, signal);
+ throw res;
+ }
}
@Override
public @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
@NonNull String mimeTypeFilter, @Nullable Bundle opts,
@Nullable CancellationSignal signal) throws RemoteException, FileNotFoundException {
- final AssetFileDescriptor res = delegate.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
- log("openTypedAssetFile", res, uri, mimeTypeFilter, opts, signal);
- return res;
+ try {
+ final AssetFileDescriptor res = delegate.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
+ log("openTypedAssetFile", res, uri, mimeTypeFilter, opts, signal);
+ return res;
+ } catch (Exception res) {
+ log("openTypedAssetFile", res, uri, mimeTypeFilter, opts, signal);
+ throw res;
+ }
}
@Override
public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
@NonNull ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException {
- final ContentProviderResult[] res = delegate.applyBatch(authority, operations);
- log("applyBatch", res, authority, operations);
- return res;
+ try {
+ final ContentProviderResult[] res = delegate.applyBatch(authority, operations);
+ log("applyBatch", res, authority, operations);
+ return res;
+ } catch (Exception res) {
+ log("applyBatch", res, authority, operations);
+ throw res;
+ }
}
@Override
public @Nullable Bundle call(@NonNull String authority, @NonNull String method,
@Nullable String arg, @Nullable Bundle extras) throws RemoteException {
- final Bundle res = delegate.call(authority, method, arg, extras);
- log("call", res, authority, method, arg, extras);
- return res;
+ try {
+ final Bundle res = delegate.call(authority, method, arg, extras);
+ log("call", res, authority, method, arg, extras);
+ return res;
+ } catch (Exception res) {
+ log("call", res, authority, method, arg, extras);
+ throw res;
+ }
}
}
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 8e72fa5..ceea043 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -16,12 +16,14 @@
package android.content.om;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import java.util.List;
@@ -96,6 +98,28 @@
}
/**
+ * Returns information about the overlay with the given package name for
+ * the specified user.
+ *
+ * @param packageName The name of the package.
+ * @param userHandle The user to get the OverlayInfos for.
+ * @return An OverlayInfo object; if no overlays exist with the
+ * requested package name, null is returned.
+ *
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public OverlayInfo getOverlayInfo(@NonNull final String packageName,
+ @NonNull final UserHandle userHandle) {
+ try {
+ return mService.getOverlayInfo(packageName, userHandle.myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns information about all overlays for the given target package for
* the specified user. The returned list is ordered according to the
* overlay priority with the highest priority at the end of the list.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 706cbbf..068a93a 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -671,6 +671,14 @@
*/
public static final int PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE = 1 << 27;
+ /**
+ * Indicates whether this package is in fact a runtime resource overlay.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28;
+
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -683,6 +691,7 @@
PRIVATE_FLAG_HAS_DOMAIN_URLS,
PRIVATE_FLAG_HIDDEN,
PRIVATE_FLAG_INSTANT,
+ PRIVATE_FLAG_IS_RESOURCE_OVERLAY,
PRIVATE_FLAG_ISOLATED_SPLIT_LOADING,
PRIVATE_FLAG_OEM,
PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,
@@ -2023,6 +2032,14 @@
}
/**
+ * Returns true if the package has declared in its manifest that it is a
+ * runtime resource overlay.
+ */
+ public boolean isResourceOverlay() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY) != 0;
+ }
+
+ /**
* @hide
*/
@Override protected ApplicationInfo getApplicationInfo() {
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index fd3529b..464e866 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -742,7 +742,7 @@
String getAppPredictionServicePackageName();
- String getContentCaptureServicePackageName();
+ String getSystemCaptionsServicePackageName();
String getIncidentReportApproverPackageName();
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 2a19763..954deac 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -142,17 +142,6 @@
public static final String EXTRA_PIN_ITEM_REQUEST =
"android.content.pm.extra.PIN_ITEM_REQUEST";
- /**
- * Metadata key that specifies vouched certs, so any apps signed by a cert in vouched certs
- * will not show hidden icon in launcher even it does not have a launcher visible activity.
- *
- * If an app has this metadata in manifest, it won't be eligible to hide its icon even if its
- * cert is in vouched certs list.
- *
- * @hide
- */
- public static final String VOUCHED_CERTS_KEY = "vouched_certs";
-
private final Context mContext;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final ILauncherApps mService;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 33b9c72..3edd17a 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1448,19 +1448,6 @@
}
/**
- * Request that rollbacks be enabled for the given upgrade.
- *
- * @removed
- * @deprecated use {@link #setEnableRollback(boolean)} instead.
- * @hide
- */
- @Deprecated
- @SystemApi
- public void setEnableRollback() {
- installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
- }
-
- /**
* Request that rollbacks be enabled or disabled for the given upgrade.
*
* @param enable set to {@code true} to enable, {@code false} to disable
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 99324ba..fa5247c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2589,14 +2589,6 @@
public static final String FEATURE_PC = "android.hardware.type.pc";
/**
- * Feature for {@link #getSystemAvailableFeatures} and
- * {@link #hasSystemFeature}: This is a foldable device. Properties such as
- * the display size may change in response to being folded.
- */
- @SdkConstant(SdkConstantType.FEATURE)
- public static final String FEATURE_FOLDABLE = "android.hardware.type.foldable";
-
- /**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports printing.
*/
@@ -3073,6 +3065,15 @@
public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 9;
/**
+ * Permission flag: The permission should not be shown in the UI.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int FLAG_PERMISSION_HIDDEN = 1 << 10;
+
+ /**
* Mask for all permission flags present in Android P
*
* @deprecated This constant does not contain useful information and should never have been
@@ -3090,7 +3091,7 @@
*
* @hide
*/
- public static final int MASK_PERMISSION_FLAGS_ALL = 0x3FF;
+ public static final int MASK_PERMISSION_FLAGS_ALL = 0x7FF;
/**
* Injected activity in app that forwards user to setting activity of that app.
@@ -3801,6 +3802,7 @@
FLAG_PERMISSION_GRANTED_BY_DEFAULT,
FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED,
FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED,
+ FLAG_PERMISSION_HIDDEN,
/*
FLAG_PERMISSION_REVOKE_WHEN_REQUESED
*/
@@ -6594,6 +6596,7 @@
case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED: return "REVOKE_WHEN_REQUESTED";
case FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED: return "USER_SENSITIVE_WHEN_GRANTED";
case FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED: return "USER_SENSITIVE_WHEN_DENIED";
+ case FLAG_PERMISSION_HIDDEN: return "HIDDEN";
default: return Integer.toString(flag);
}
}
@@ -6863,9 +6866,9 @@
*
* @hide
*/
- public String getContentCaptureServicePackageName() {
+ public String getSystemCaptionsServicePackageName() {
throw new UnsupportedOperationException(
- "getContentCaptureServicePackageName not implemented in subclass");
+ "getSystemCaptionsServicePackageName not implemented in subclass");
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9d0ece0..743a302 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2108,6 +2108,9 @@
return null;
}
+ pkg.applicationInfo.privateFlags |=
+ ApplicationInfo.PRIVATE_FLAG_IS_RESOURCE_OVERLAY;
+
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals(TAG_KEY_SETS)) {
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 13c49a0..3488cc3 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -307,9 +307,9 @@
@Override
public String toString() {
- return "SharedLibraryInfo[name:" + mName + ", type:" + typeToString(mType)
+ return "SharedLibraryInfo{name:" + mName + ", type:" + typeToString(mType)
+ ", version:" + mVersion + (!getDependentPackages().isEmpty()
- ? " has dependents" : "");
+ ? " has dependents" : "") + "}";
}
@Override
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 7b61807..1f82fa6 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1270,8 +1270,8 @@
* system services even after it has been unpublished as a dynamic shortcut.
*/
@NonNull
- public Builder setLongLived() {
- mIsLongLived = true;
+ public Builder setLongLived(boolean londLived) {
+ mIsLongLived = londLived;
return this;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 6729242..6b8416d 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -191,9 +191,9 @@
/**
* Return a global shared Resources object that provides access to only
- * system resources (no application resources), and is not configured for
- * the current screen (can not use dimension units, does not change based
- * on orientation, etc).
+ * system resources (no application resources), is not configured for the
+ * current screen (can not use dimension units, does not change based on
+ * orientation, etc), and is not affected by Runtime Resource Overlay.
*/
public static Resources getSystem() {
synchronized (sSync) {
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index 9038b03..d54a6fe 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -24,6 +24,7 @@
import android.annotation.TestApi;
import android.content.Context;
import android.content.IntentSender;
+import android.content.pm.PackageInstaller;
import android.content.pm.ParceledListSlice;
import android.content.pm.VersionedPackage;
import android.os.RemoteException;
@@ -48,6 +49,24 @@
private final String mCallerPackageName;
private final IRollbackManager mBinder;
+ /**
+ * Lifetime duration of rollback packages in millis. A rollback will be available for
+ * at most that duration of time after a package is installed with
+ * {@link PackageInstaller.SessionParams#setEnableRollback()}.
+ *
+ * <p>If flag value is negative, the default value will be assigned.
+ *
+ * @see RollbackManager
+ *
+ * Flag type: {@code long}
+ * Namespace: NAMESPACE_ROLLBACK_BOOT
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String PROPERTY_ROLLBACK_LIFETIME_MILLIS =
+ "rollback_lifetime_in_millis";
+
/** {@hide} */
public RollbackManager(Context context, IRollbackManager binder) {
mCallerPackageName = context.getPackageName();
@@ -57,10 +76,12 @@
/**
* Returns a list of all currently available rollbacks.
*
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+ })
@NonNull
public List<RollbackInfo> getAvailableRollbacks() {
try {
@@ -85,10 +106,12 @@
* rolled back from.
*
* @return the recently committed rollbacks
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+ })
public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
try {
return mBinder.getRecentlyExecutedRollbacks().getList();
@@ -171,10 +194,12 @@
* @param statusReceiver where to deliver the results. Intents sent to
* this receiver contain {@link #EXTRA_STATUS}
* and {@link #EXTRA_STATUS_MESSAGE}.
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_ROLLBACKS,
+ android.Manifest.permission.TEST_MANAGE_ROLLBACKS
+ })
public void commitRollback(int rollbackId, @NonNull List<VersionedPackage> causePackages,
@NonNull IntentSender statusReceiver) {
try {
@@ -191,12 +216,11 @@
* across device reboot, by simulating what happens on reboot without
* actually rebooting the device.
*
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
@TestApi
public void reloadPersistedData() {
try {
@@ -213,12 +237,11 @@
* recently committed rollbacks that contain the given package.
*
* @param packageName the name of the package to expire data for.
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
+ * @throws SecurityException if the caller does not have appropriate permissions.
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @RequiresPermission(android.Manifest.permission.TEST_MANAGE_ROLLBACKS)
@TestApi
public void expireRollbackForPackage(@NonNull String packageName) {
try {
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index d796003..5e2875d 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -176,6 +176,6 @@
/** @hide */
public static boolean checkDbWipe() {
- return true;
+ return false;
}
}
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 6ea35f0..bae0fd3 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -315,7 +315,7 @@
/**
* The sensor is dirty. The user should be informed to clean the sensor.
*/
- public static final int SENSOR_DIRTY = 21;
+ public static final int FACE_ACQUIRED_SENSOR_DIRTY = 21;
/**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index e751b2c..08035972 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -523,6 +523,11 @@
* cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
* CharSequence)}.
*
+ * Note: Applications generally should not cancel and start authentication in quick succession.
+ * For example, to properly handle authentication across configuration changes, it's recommended
+ * to use BiometricPrompt in a fragment with setRetainInstance(true). By doing so, the
+ * application will not need to cancel/restart authentication during the configuration change.
+ *
* @throws IllegalArgumentException If any of the arguments are null
*
* @param crypto Object associated with the call
@@ -568,6 +573,11 @@
* authentication. The interrupted client will receive a cancelled notification through {@link
* AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
*
+ * Note: Applications generally should not cancel and start authentication in quick succession.
+ * For example, to properly handle authentication across configuration changes, it's recommended
+ * to use BiometricPrompt in a fragment with setRetainInstance(true). By doing so, the
+ * application will not need to cancel/restart authentication during the configuration change.
+ *
* @throws IllegalArgumentException If any of the arguments are null
*
* @param cancel An object that can be used to cancel authentication
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 7ae673c..c39796b 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -336,6 +336,7 @@
* <li>{@link RecommendedStreamConfigurationMap#USECASE_SNAPSHOT}</li>
* <li>{@link RecommendedStreamConfigurationMap#USECASE_RAW}</li>
* <li>{@link RecommendedStreamConfigurationMap#USECASE_ZSL}</li>
+ * <li>{@link RecommendedStreamConfigurationMap#USECASE_LOW_LATENCY_SNAPSHOT}</li>
* </ul>
* </p>
*
@@ -400,7 +401,7 @@
public @Nullable RecommendedStreamConfigurationMap getRecommendedStreamConfigurationMap(
@RecommendedStreamConfigurationMap.RecommendedUsecase int usecase) {
if (((usecase >= RecommendedStreamConfigurationMap.USECASE_PREVIEW) &&
- (usecase <= RecommendedStreamConfigurationMap.USECASE_RAW)) ||
+ (usecase <= RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT)) ||
((usecase >= RecommendedStreamConfigurationMap.USECASE_VENDOR_START) &&
(usecase < RecommendedStreamConfigurationMap.MAX_USECASE_COUNT))) {
if (mRecommendedConfigurations == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 1cdf235..e909c00 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1113,8 +1113,10 @@
depthStreamDurationList.get(i), depthStreamStallList.get(i), depthScData);
}
- if ((scData.streamConfigurationArray == null) &&
- (depthScData.streamConfigurationArray == null)) {
+ if ((scData.streamConfigurationArray == null ||
+ scData.streamConfigurationArray.length == 0) &&
+ (depthScData.streamConfigurationArray == null ||
+ depthScData.streamConfigurationArray.length == 0)) {
recommendedConfigurations.add(null);
continue;
}
@@ -1125,6 +1127,7 @@
switch (i) {
case RecommendedStreamConfigurationMap.USECASE_PREVIEW:
case RecommendedStreamConfigurationMap.USECASE_RAW:
+ case RecommendedStreamConfigurationMap.USECASE_LOW_LATENCY_SNAPSHOT:
case RecommendedStreamConfigurationMap.USECASE_VIDEO_SNAPSHOT:
map = new StreamConfigurationMap(scData.streamConfigurationArray,
scData.minDurationArray, scData.stallDurationArray,
diff --git a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
index 068c0ce..2d72598 100644
--- a/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/RecommendedStreamConfigurationMap.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.ImageFormat;
+import android.graphics.ImageFormat.Format;
import android.graphics.PixelFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
@@ -137,6 +138,17 @@
public static final int USECASE_RAW = 0x5;
/**
+ * The recommended stream configuration map for use case low latency snapshot must contain
+ * subset of configurations with end-to-end latency that does not exceed 200 ms. under standard
+ * operating conditions (reasonable light levels, not loaded system). The expected output format
+ * will be primarily {@link android.graphics.ImageFormat#JPEG} however other image formats can
+ * be present as well. Even if available for the camera device, high speed and input
+ * configurations will be absent. This suggested configuration map may be absent on some devices
+ * that can not support any low latency requests.
+ */
+ public static final int USECASE_LOW_LATENCY_SNAPSHOT = 0x6;
+
+ /**
* Device specific use cases.
* @hide
*/
@@ -150,7 +162,8 @@
USECASE_VIDEO_SNAPSHOT,
USECASE_SNAPSHOT,
USECASE_ZSL,
- USECASE_RAW })
+ USECASE_RAW,
+ USECASE_LOW_LATENCY_SNAPSHOT})
public @interface RecommendedUsecase {};
/**
@@ -214,7 +227,7 @@
*
* @return a non-modifiable set of Integer formats
*/
- public @Nullable Set<Integer> getValidOutputFormatsForInput(int inputFormat) {
+ public @Nullable Set<Integer> getValidOutputFormatsForInput(@Format int inputFormat) {
return getUnmodifiableIntegerSet(mRecommendedMap.getValidOutputFormatsForInput(
inputFormat));
}
@@ -250,7 +263,7 @@
* @param format a format from {@link #getInputFormats}
* @return a non-modifiable set of sizes, or {@code null} if the format was not available.
*/
- public @Nullable Set<Size> getInputSizes(int format) {
+ public @Nullable Set<Size> getInputSizes(@Format int format) {
return getUnmodifiableSizeSet(mRecommendedMap.getInputSizes(format));
}
@@ -272,7 +285,7 @@
* if the image format was not a defined named constant
* from either {@link ImageFormat} or {@link PixelFormat}
*/
- public boolean isOutputSupportedFor(int format) {
+ public boolean isOutputSupportedFor(@Format int format) {
return mRecommendedMap.isOutputSupportedFor(format);
}
@@ -288,7 +301,7 @@
* @return a non-modifiable set of supported sizes,
* or {@code null} if the {@code format} is not a supported output
*/
- public @Nullable Set<Size> getOutputSizes(int format) {
+ public @Nullable Set<Size> getOutputSizes(@Format int format) {
return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(format));
}
@@ -372,7 +385,7 @@
* @return a non-modifiable set of supported slower high-resolution sizes, or {@code null} if
* the BURST_CAPTURE capability is not supported
*/
- public @Nullable Set<Size> getHighResolutionOutputSizes(int format) {
+ public @Nullable Set<Size> getHighResolutionOutputSizes(@Format int format) {
return getUnmodifiableSizeSet(mRecommendedMap.getHighResolutionOutputSizes(format));
}
@@ -392,7 +405,8 @@
*
* @throws IllegalArgumentException if {@code format} or {@code size} was not supported
*/
- public @IntRange(from = 0) long getOutputMinFrameDuration(int format, @NonNull Size size) {
+ public @IntRange(from = 0) long getOutputMinFrameDuration(@Format int format,
+ @NonNull Size size) {
return mRecommendedMap.getOutputMinFrameDuration(format, size);
}
@@ -409,7 +423,7 @@
*
* @throws IllegalArgumentException if {@code format} or {@code size} was not supported
*/
- public @IntRange(from = 0) long getOutputStallDuration(int format, @NonNull Size size) {
+ public @IntRange(from = 0) long getOutputStallDuration(@Format int format, @NonNull Size size) {
return mRecommendedMap.getOutputStallDuration(format, size);
}
@@ -425,7 +439,7 @@
* a non-modifiable set of supported sizes for {@link ImageFormat#PRIVATE} format,
* or {@code null} if the {@code klass} is not a supported output.
*/
- public <T> @Nullable Set<Size> getOutputSizes(@NonNull Class<T> klass) {
+ public @Nullable <T> Set<Size> getOutputSizes(@NonNull Class<T> klass) {
if (mSupportsPrivate) {
return getUnmodifiableSizeSet(mRecommendedMap.getOutputSizes(klass));
}
@@ -448,7 +462,7 @@
*
* @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
*/
- public <T> @IntRange(from = 0) long getOutputMinFrameDuration(@NonNull final Class<T> klass,
+ public @IntRange(from = 0) <T> long getOutputMinFrameDuration(@NonNull final Class<T> klass,
@NonNull final Size size) {
if (mSupportsPrivate) {
return mRecommendedMap.getOutputMinFrameDuration(klass, size);
@@ -471,7 +485,7 @@
*
* @throws IllegalArgumentException if {@code klass} or {@code size} was not supported
*/
- public <T> @IntRange(from = 0) long getOutputStallDuration(@NonNull final Class<T> klass,
+ public @IntRange(from = 0) <T> long getOutputStallDuration(@NonNull final Class<T> klass,
@NonNull final Size size) {
if (mSupportsPrivate) {
return mRecommendedMap.getOutputStallDuration(klass, size);
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index 7fa1cfb..21fcc63 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -80,15 +80,23 @@
* Histogram counting how many times a pixel of a given value was displayed onscreen for the
* Value component of HSV if the device supports color sampling, if the device does not support
* color sampling the value will be null.
+ *
* The buckets of the histogram are evenly weighted, the number of buckets is device specific.
- * For example if we had {10, 6, 4, 1} this means that 10 pixels were in the range
- * [0x00,0x3f], 6 pixels were in the range [0x40,0x7f] etc.
+ * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+ * for 1 millisecond.
+ * For example if we had {100, 50, 30, 20}, value component was onscreen for 100 pixel
+ * milliseconds in range 0x00->0x3F, 30 pixel milliseconds in range 0x40->0x7F, etc.
+ *
+ * {@see #colorSampleDuration}
*/
@Nullable
public final long[] colorValueBuckets;
/**
- * How many milliseconds of data are contained in the colorValueBuckets.
+ * How many milliseconds of data are contained in the colorValueBuckets, if the device does
+ * not support color sampling the value will be 0L.
+ *
+ * {@see #colorValueBuckets}
*/
public final long colorSampleDuration;
@@ -283,7 +291,8 @@
return this;
}
- /** {@see BrightnessChangeEvent#valueBuckets} */
+ /** {@see BrightnessChangeEvent#colorValueBuckets}
+ * {@see BrightnessChangeEvent#colorSampleDuration} */
public Builder setColorValues(@NonNull long[] colorValueBuckets, long colorSampleDuration) {
Objects.requireNonNull(colorValueBuckets);
mColorValueBuckets = colorValueBuckets;
diff --git a/core/java/android/hardware/display/DisplayedContentSample.java b/core/java/android/hardware/display/DisplayedContentSample.java
index 0610377..4a429bb 100644
--- a/core/java/android/hardware/display/DisplayedContentSample.java
+++ b/core/java/android/hardware/display/DisplayedContentSample.java
@@ -30,12 +30,14 @@
* Construct an object representing a color histogram of pixels that were displayed on screen.
*
* @param numFrames The number of frames represented by this sample.
- * @param mSamplesComponent0 is a histogram counting how many times a pixel of a given value
- * was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the histogram are evenly
- * weighted, the number of buckets is device specific.
- * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that 10 red pixels were
- * displayed onscreen in range 0x00->0x3F, 6 red pixels were displayed onscreen in range
- * 0x40->0x7F, etc.
+ * @param mSamplesComponent0 is a histogram counting how many times and for how long a pixel
+ * of a given value was displayed onscreen for FORMAT_COMPONENT_0. The buckets of the
+ * histogram are evenly weighted, the number of buckets is device specific.
+ * The units are in pixels * milliseconds, with 1 pixel millisecond being 1 pixel displayed
+ * onscreen for 1ms.
+ * eg, for RGBA_8888, if sampleComponent0 is {100, 50, 30, 20}, then red component was
+ * onscreen for 100 pixel milliseconds in range 0x00->0x3F, 30 pixel milliseconds in
+ * range 0x40->0x7F, etc.
* @param mSamplesComponent1 is the same sample definition as sampleComponent0, but for the
* second component of format.
* @param mSamplesComponent2 is the same sample definition as sampleComponent0, but for the
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 139a5ee..3e8c334 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -634,6 +634,8 @@
return context.getString(R.string.face_acquired_obscured);
case FACE_ACQUIRED_START:
return null;
+ case FACE_ACQUIRED_SENSOR_DIRTY:
+ return context.getString(R.string.face_acquired_sensor_dirty);
case FACE_ACQUIRED_VENDOR: {
String[] msgArray = context.getResources().getStringArray(
R.array.face_acquired_vendor);
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index f208724..3e4e35a 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -15,6 +15,7 @@
*/
package android.net;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.IBinder;
@@ -29,15 +30,33 @@
* {@code ACTION_CAPTIVE_PORTAL_SIGN_IN} activity.
*/
public class CaptivePortal implements Parcelable {
- /** @hide */
+ /**
+ * Response code from the captive portal application, indicating that the portal was dismissed
+ * and the network should be re-validated.
+ * @see ICaptivePortal#appResponse(int)
+ * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+ * @hide
+ */
@SystemApi
@TestApi
public static final int APP_RETURN_DISMISSED = 0;
- /** @hide */
+ /**
+ * Response code from the captive portal application, indicating that the user did not login and
+ * does not want to use the captive portal network.
+ * @see ICaptivePortal#appResponse(int)
+ * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+ * @hide
+ */
@SystemApi
@TestApi
public static final int APP_RETURN_UNWANTED = 1;
- /** @hide */
+ /**
+ * Response code from the captive portal application, indicating that the user does not wish to
+ * login but wants to use the captive portal network as-is.
+ * @see ICaptivePortal#appResponse(int)
+ * @see android.net.INetworkMonitor#notifyCaptivePortalAppFinished(int)
+ * @hide
+ */
@SystemApi
@TestApi
public static final int APP_RETURN_WANTED_AS_IS = 2;
@@ -47,7 +66,7 @@
/** @hide */
@SystemApi
@TestApi
- public CaptivePortal(IBinder binder) {
+ public CaptivePortal(@NonNull IBinder binder) {
mBinder = binder;
}
@@ -124,7 +143,7 @@
*/
@SystemApi
@TestApi
- public void logEvent(int eventId, String packageName) {
+ public void logEvent(int eventId, @NonNull String packageName) {
try {
ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d08379f..e5802c2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2816,23 +2816,6 @@
}
/**
- * @removed
- * @deprecated This API would be removed when all of caller has been updated.
- * */
- @Deprecated
- public abstract static class TetheringEntitlementValueListener {
- /**
- * Called to notify entitlement result.
- *
- * @param resultCode a int value of entitlement result. It may be one of
- * {@link #TETHER_ERROR_NO_ERROR},
- * {@link #TETHER_ERROR_PROVISION_FAILED}, or
- * {@link #TETHER_ERROR_ENTITLEMENT_UNKONWN}.
- */
- public void onEntitlementResult(int resultCode) {}
- }
-
- /**
* Get the last value of the entitlement check on this downstream. If the cached value is
* {@link #TETHER_ERROR_NO_ERROR} or showEntitlementUi argument is false, it just return the
* cached value. Otherwise, a UI-based entitlement check would be performed. It is not
@@ -2878,31 +2861,6 @@
}
/**
- * @removed
- * @deprecated This API would be removed when all of caller has been updated.
- * */
- @Deprecated
- public void getLatestTetheringEntitlementValue(int type, boolean showEntitlementUi,
- @NonNull final TetheringEntitlementValueListener listener, @Nullable Handler handler) {
- Preconditions.checkNotNull(listener, "TetheringEntitlementValueListener cannot be null.");
- ResultReceiver wrappedListener = new ResultReceiver(handler) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- listener.onEntitlementResult(resultCode);
- }
- };
-
- try {
- String pkgName = mContext.getOpPackageName();
- Log.i(TAG, "getLatestTetheringEntitlementValue:" + pkgName);
- mService.getLatestTetheringEntitlementResult(type, wrappedListener,
- showEntitlementUi, pkgName);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Report network connectivity status. This is currently used only
* to alter status bar UI.
* <p>This method requires the caller to hold the permission
diff --git a/core/java/android/net/DnsPacket.java b/core/java/android/net/DnsPacket.java
index 0ac02b1..83e57e0 100644
--- a/core/java/android/net/DnsPacket.java
+++ b/core/java/android/net/DnsPacket.java
@@ -71,7 +71,7 @@
}
/**
- * It's used both for DNS questions and DNS resource records.
+ * Superclass for DNS questions and DNS resource records.
*
* DNS questions (No TTL/RDATA)
* DNS resource records (With TTL/RDATA)
@@ -96,12 +96,13 @@
/**
* Create a new DnsRecord from a positioned ByteBuffer.
*
- * @param ByteBuffer input of record, must be in network byte order
- * (which is the default).
* Reads the passed ByteBuffer from its current position and decodes a DNS record.
* When this constructor returns, the reading position of the ByteBuffer has been
* advanced to the end of the DNS header record.
* This is meant to chain with other methods reading a DNS response in sequence.
+ *
+ * @param ByteBuffer input of record, must be in network byte order
+ * (which is the default).
*/
DnsRecord(int recordType, @NonNull ByteBuffer buf)
throws BufferUnderflowException, ParseException {
@@ -205,16 +206,6 @@
protected final DnsHeader mHeader;
protected final List<DnsRecord>[] mRecords;
- public static class ParseException extends Exception {
- public ParseException(String msg) {
- super(msg);
- }
-
- public ParseException(String msg, Throwable cause) {
- super(msg, cause);
- }
- }
-
protected DnsPacket(@NonNull byte[] data) throws ParseException {
if (null == data) throw new ParseException("Parse header failed, null input data");
final ByteBuffer buffer;
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index d3bc3e6..93b8cf8 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,11 +22,11 @@
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Handler;
-import android.os.MessageQueue;
+import android.os.Looper;
import android.system.ErrnoException;
import android.util.Log;
@@ -37,8 +37,7 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
-import java.util.function.Consumer;
-
+import java.util.concurrent.Executor;
/**
* Dns resolver class for asynchronous dns querying
@@ -81,66 +80,137 @@
public static final int FLAG_NO_CACHE_STORE = 1 << 1;
public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
- private static final int DNS_RAW_RESPONSE = 1;
-
private static final int NETID_UNSET = 0;
private static final DnsResolver sInstance = new DnsResolver();
/**
- * listener for receiving raw answers
- */
- public interface RawAnswerListener {
- /**
- * {@code byte[]} is {@code null} if query timed out
- */
- void onAnswer(@Nullable byte[] answer);
- }
-
- /**
- * listener for receiving parsed answers
- */
- public interface InetAddressAnswerListener {
- /**
- * Will be called exactly once with all the answers to the query.
- * size of addresses will be zero if no available answer could be parsed.
- */
- void onAnswer(@NonNull List<InetAddress> addresses);
- }
-
- /**
* Get instance for DnsResolver
*/
- public static DnsResolver getInstance() {
+ public static @NonNull DnsResolver getInstance() {
return sInstance;
}
private DnsResolver() {}
/**
- * Pass in a blob and corresponding setting,
- * get a blob back asynchronously with the entire raw answer.
+ * Answer parser for parsing raw answers
+ *
+ * @param <T> The type of the parsed answer
+ */
+ public interface AnswerParser<T> {
+ /**
+ * Creates a <T> answer by parsing the given raw answer.
+ *
+ * @param rawAnswer the raw answer to be parsed
+ * @return a parsed <T> answer
+ * @throws ParseException if parsing failed
+ */
+ @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException;
+ }
+
+ /**
+ * Base class for answer callbacks
+ *
+ * @param <T> The type of the parsed answer
+ */
+ public abstract static class AnswerCallback<T> {
+ /** @hide */
+ public final AnswerParser<T> parser;
+
+ public AnswerCallback(@NonNull AnswerParser<T> parser) {
+ this.parser = parser;
+ };
+
+ /**
+ * Success response to
+ * {@link android.net.DnsResolver#query query()}.
+ *
+ * Invoked when the answer to a query was successfully parsed.
+ *
+ * @param answer parsed answer to the query.
+ *
+ * {@see android.net.DnsResolver#query query()}
+ */
+ public abstract void onAnswer(@NonNull T answer);
+
+ /**
+ * Error response to
+ * {@link android.net.DnsResolver#query query()}.
+ *
+ * Invoked when there is no valid answer to
+ * {@link android.net.DnsResolver#query query()}
+ *
+ * @param exception a {@link ParseException} object with additional
+ * detail regarding the failure
+ */
+ public abstract void onParseException(@NonNull ParseException exception);
+
+ /**
+ * Error response to
+ * {@link android.net.DnsResolver#query query()}.
+ *
+ * Invoked if an error happens when
+ * issuing the DNS query or receiving the result.
+ * {@link android.net.DnsResolver#query query()}
+ *
+ * @param exception an {@link ErrnoException} object with additional detail
+ * regarding the failure
+ */
+ public abstract void onQueryException(@NonNull ErrnoException exception);
+ }
+
+ /**
+ * Callback for receiving raw answers
+ */
+ public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> {
+ public RawAnswerCallback() {
+ super(rawAnswer -> rawAnswer);
+ }
+ }
+
+ /**
+ * Callback for receiving parsed {@link InetAddress} answers
+ *
+ * Note that if the answer does not contain any IP addresses,
+ * onAnswer will be called with an empty list.
+ */
+ public abstract static class InetAddressAnswerCallback
+ extends AnswerCallback<List<InetAddress>> {
+ public InetAddressAnswerCallback() {
+ super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
+ }
+ }
+
+ /**
+ * Send a raw DNS query.
+ * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
*
* @param network {@link Network} specifying which network for querying.
* {@code null} for query on default network.
* @param query blob message
* @param flags flags as a combination of the FLAGS_* constants
- * @param handler {@link Handler} to specify the thread
- * upon which the {@link RawAnswerListener} will be invoked.
- * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param callback an {@link AnswerCallback} which will be called to notify the caller
* of the result of dns query.
*/
- public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
- @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
- final FileDescriptor queryfd = resNetworkSend((network != null
+ public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+ final FileDescriptor queryfd;
+ try {
+ queryfd = resNetworkSend((network != null
? network.netId : NETID_UNSET), query, query.length, flags);
- registerFDListener(handler.getLooper().getQueue(), queryfd,
- answerbuf -> listener.onAnswer(answerbuf));
+ } catch (ErrnoException e) {
+ callback.onQueryException(e);
+ return;
+ }
+
+ registerFDListener(executor, queryfd, callback);
}
/**
- * Pass in a domain name and corresponding setting,
- * get a blob back asynchronously with the entire raw answer.
+ * Send a DNS query with the specified name, class and query type.
+ * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
*
* @param network {@link Network} specifying which network for querying.
* {@code null} for query on default network.
@@ -148,74 +218,53 @@
* @param nsClass dns class as one of the CLASS_* constants
* @param nsType dns resource record (RR) type as one of the TYPE_* constants
* @param flags flags as a combination of the FLAGS_* constants
- * @param handler {@link Handler} to specify the thread
- * upon which the {@link RawAnswerListener} will be invoked.
- * @param listener a {@link RawAnswerListener} which will be called to notify the caller
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param callback an {@link AnswerCallback} which will be called to notify the caller
* of the result of dns query.
*/
- public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass,
- @QueryType int nsType, @QueryFlag int flags,
- @NonNull Handler handler, @NonNull RawAnswerListener listener) throws ErrnoException {
- final FileDescriptor queryfd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
- registerFDListener(handler.getLooper().getQueue(), queryfd,
- answerbuf -> listener.onAnswer(answerbuf));
+ public <T> void query(@Nullable Network network, @NonNull String domain,
+ @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback<T> callback) {
+ final FileDescriptor queryfd;
+ try {
+ queryfd = resNetworkQuery((network != null
+ ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+ } catch (ErrnoException e) {
+ callback.onQueryException(e);
+ return;
+ }
+ registerFDListener(executor, queryfd, callback);
}
- /**
- * Pass in a domain name and corresponding setting,
- * get back a set of InetAddresses asynchronously.
- *
- * @param network {@link Network} specifying which network for querying.
- * {@code null} for query on default network.
- * @param domain domain name for querying
- * @param flags flags as a combination of the FLAGS_* constants
- * @param handler {@link Handler} to specify the thread
- * upon which the {@link InetAddressAnswerListener} will be invoked.
- * @param listener an {@link InetAddressAnswerListener} which will be called to
- * notify the caller of the result of dns query.
- *
- */
- public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
- @NonNull Handler handler, @NonNull InetAddressAnswerListener listener)
- throws ErrnoException {
- final FileDescriptor v4fd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
- final FileDescriptor v6fd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
-
- final InetAddressAnswerAccumulator accmulator =
- new InetAddressAnswerAccumulator(2, listener);
- final Consumer<byte[]> consumer = answerbuf ->
- accmulator.accumulate(parseAnswers(answerbuf));
-
- registerFDListener(handler.getLooper().getQueue(), v4fd, consumer);
- registerFDListener(handler.getLooper().getQueue(), v6fd, consumer);
- }
-
- private void registerFDListener(@NonNull MessageQueue queue,
- @NonNull FileDescriptor queryfd, @NonNull Consumer<byte[]> answerConsumer) {
- queue.addOnFileDescriptorEventListener(
+ private <T> void registerFDListener(@NonNull Executor executor,
+ @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+ Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
queryfd,
FD_EVENTS,
(fd, events) -> {
- byte[] answerbuf = null;
- try {
- // TODO: Implement result function in Java side instead of using JNI
- // Because JNI method close fd prior than unregistering fd on
- // event listener.
- answerbuf = resNetworkResult(fd);
- } catch (ErrnoException e) {
- Log.e(TAG, "resNetworkResult:" + e.toString());
- }
- answerConsumer.accept(answerbuf);
+ executor.execute(() -> {
+ byte[] answerbuf = null;
+ try {
+ answerbuf = resNetworkResult(fd);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "resNetworkResult:" + e.toString());
+ answerCallback.onQueryException(e);
+ return;
+ }
+ try {
+ answerCallback.onAnswer(
+ answerCallback.parser.parse(answerbuf));
+ } catch (ParseException e) {
+ answerCallback.onParseException(e);
+ }
+ });
// Unregister this fd listener
return 0;
});
}
- private class DnsAddressAnswer extends DnsPacket {
+ private static class DnsAddressAnswer extends DnsPacket {
private static final String TAG = "DnsResolver.DnsAddressAnswer";
private static final boolean DBG = false;
@@ -226,12 +275,6 @@
if ((mHeader.flags & (1 << 15)) == 0) {
throw new ParseException("Not an answer packet");
}
- if (mHeader.rcode != 0) {
- throw new ParseException("Response error, rcode:" + mHeader.rcode);
- }
- if (mHeader.getRecordCount(ANSECTION) == 0) {
- throw new ParseException("No available answer");
- }
if (mHeader.getRecordCount(QDSECTION) == 0) {
throw new ParseException("No question found");
}
@@ -241,6 +284,8 @@
public @NonNull List<InetAddress> getAddresses() {
final List<InetAddress> results = new ArrayList<InetAddress>();
+ if (mHeader.getRecordCount(ANSECTION) == 0) return results;
+
for (final DnsRecord ansSec : mRecords[ANSECTION]) {
// Only support A and AAAA, also ignore answers if query type != answer type.
int nsType = ansSec.nsType;
@@ -259,34 +304,4 @@
}
}
- private @Nullable List<InetAddress> parseAnswers(@Nullable byte[] data) {
- try {
- return (data == null) ? null : new DnsAddressAnswer(data).getAddresses();
- } catch (DnsPacket.ParseException e) {
- Log.e(TAG, "Parse answer fail " + e.getMessage());
- return null;
- }
- }
-
- private class InetAddressAnswerAccumulator {
- private final List<InetAddress> mAllAnswers;
- private final InetAddressAnswerListener mAnswerListener;
- private final int mTargetAnswerCount;
- private int mReceivedAnswerCount = 0;
-
- InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerListener listener) {
- mTargetAnswerCount = size;
- mAllAnswers = new ArrayList<>();
- mAnswerListener = listener;
- }
-
- public void accumulate(@Nullable List<InetAddress> answer) {
- if (null != answer) {
- mAllAnswers.addAll(answer);
- }
- if (++mReceivedAnswerCount == mTargetAnswerCount) {
- mAnswerListener.onAnswer(mAllAnswers);
- }
- }
- }
}
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
similarity index 73%
copy from core/java/android/net/ProxyInfoParcelable.aidl
copy to core/java/android/net/IIpMemoryStoreCallbacks.aidl
index 59fd846..53108db 100644
--- a/core/java/android/net/ProxyInfoParcelable.aidl
+++ b/core/java/android/net/IIpMemoryStoreCallbacks.aidl
@@ -5,20 +5,20 @@
* 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
+ * 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.net;
-parcelable ProxyInfoParcelable {
- String host;
- int port;
- String[] exclusionList;
- String pacFileUrl;
+import android.net.IIpMemoryStore;
+
+/** {@hide} */
+oneway interface IIpMemoryStoreCallbacks {
+ void onIpMemoryStoreFetched(in IIpMemoryStore ipMemoryStore);
}
diff --git a/core/java/android/net/INetworkMonitor.aidl b/core/java/android/net/INetworkMonitor.aidl
index 5d1ab98..1b0e1d7 100644
--- a/core/java/android/net/INetworkMonitor.aidl
+++ b/core/java/android/net/INetworkMonitor.aidl
@@ -41,7 +41,7 @@
void start();
void launchCaptivePortalApp();
void notifyCaptivePortalAppFinished(int response);
- void notifyAcceptPartialConnectivity();
+ void setAcceptPartialConnectivity();
void forceReevaluation(int uid);
void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
void notifyDnsResponse(int returnCode);
diff --git a/core/java/android/net/INetworkStackConnector.aidl b/core/java/android/net/INetworkStackConnector.aidl
index e052488..3751c36 100644
--- a/core/java/android/net/INetworkStackConnector.aidl
+++ b/core/java/android/net/INetworkStackConnector.aidl
@@ -15,8 +15,9 @@
*/
package android.net;
+import android.net.IIpMemoryStoreCallbacks;
import android.net.INetworkMonitorCallbacks;
-import android.net.NetworkParcelable;
+import android.net.Network;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IIpClientCallbacks;
@@ -25,7 +26,7 @@
oneway interface INetworkStackConnector {
void makeDhcpServer(in String ifName, in DhcpServingParamsParcel params,
in IDhcpServerCallbacks cb);
- void makeNetworkMonitor(in NetworkParcelable network, String name,
- in INetworkMonitorCallbacks cb);
+ void makeNetworkMonitor(in Network network, String name, in INetworkMonitorCallbacks cb);
void makeIpClient(in String ifName, in IIpClientCallbacks callbacks);
-}
\ No newline at end of file
+ void fetchIpMemoryStore(in IIpMemoryStoreCallbacks cb);
+}
diff --git a/core/java/android/net/InitialConfigurationParcelable.aidl b/core/java/android/net/InitialConfigurationParcelable.aidl
index bdda3559..3fa88c3 100644
--- a/core/java/android/net/InitialConfigurationParcelable.aidl
+++ b/core/java/android/net/InitialConfigurationParcelable.aidl
@@ -16,12 +16,12 @@
package android.net;
-import android.net.IpPrefixParcelable;
-import android.net.LinkAddressParcelable;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
parcelable InitialConfigurationParcelable {
- LinkAddressParcelable[] ipAddresses;
- IpPrefixParcelable[] directlyConnectedRoutes;
+ LinkAddress[] ipAddresses;
+ IpPrefix[] directlyConnectedRoutes;
String[] dnsServers;
String gateway;
}
\ No newline at end of file
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index c638491..c97b37b 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -19,11 +19,9 @@
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
import com.google.android.collect.Sets;
-import java.net.InetAddress;
import java.util.HashSet;
/**
@@ -117,40 +115,6 @@
}
/**
- * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
- */
- public static InterfaceConfiguration fromParcel(InterfaceConfigurationParcel p) {
- InterfaceConfiguration cfg = new InterfaceConfiguration();
- cfg.setHardwareAddress(p.hwAddr);
-
- final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
- cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
- for (String flag : p.flags) {
- cfg.setFlag(flag);
- }
-
- return cfg;
- }
-
- /**
- * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
- */
- public InterfaceConfigurationParcel toParcel(String iface) {
- InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
- cfgParcel.ifName = iface;
- if (!TextUtils.isEmpty(mHwAddr)) {
- cfgParcel.hwAddr = mHwAddr;
- } else {
- cfgParcel.hwAddr = "";
- }
- cfgParcel.ipv4Addr = mAddr.getAddress().getHostAddress();
- cfgParcel.prefixLength = mAddr.getPrefixLength();
- cfgParcel.flags = mFlags.toArray(EMPTY_STRING_ARRAY);
-
- return cfgParcel;
- }
-
- /**
* This function determines if the interface is up and has a valid IP
* configuration (IP address has a non zero octet).
*
diff --git a/core/java/android/net/IpPrefix.aidl b/core/java/android/net/IpPrefix.aidl
index 837db5f..0d70f2a 100644
--- a/core/java/android/net/IpPrefix.aidl
+++ b/core/java/android/net/IpPrefix.aidl
@@ -17,4 +17,6 @@
package android.net;
-parcelable IpPrefix cpp_header "binder/IpPrefix.h";
+// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
+// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
+@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
diff --git a/core/java/android/net/IpPrefixParcelable.aidl b/core/java/android/net/IpPrefixParcelable.aidl
deleted file mode 100644
index 93a8d41..0000000
--- a/core/java/android/net/IpPrefixParcelable.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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 android.net;
-
-parcelable IpPrefixParcelable {
- String address;
- int prefixLength;
-}
\ No newline at end of file
diff --git a/core/java/android/net/LinkAddress.aidl b/core/java/android/net/LinkAddress.aidl
index e7d8646..9c804db 100644
--- a/core/java/android/net/LinkAddress.aidl
+++ b/core/java/android/net/LinkAddress.aidl
@@ -17,5 +17,5 @@
package android.net;
-parcelable LinkAddress;
+@JavaOnlyStableParcelable parcelable LinkAddress;
diff --git a/core/java/android/net/LinkAddressParcelable.aidl b/core/java/android/net/LinkAddressParcelable.aidl
deleted file mode 100644
index af8e79b..0000000
--- a/core/java/android/net/LinkAddressParcelable.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 android.net;
-
-parcelable LinkAddressParcelable {
- String address;
- int prefixLength;
- int flags;
- int scope;
-}
\ No newline at end of file
diff --git a/core/java/android/net/LinkProperties.aidl b/core/java/android/net/LinkProperties.aidl
index 3cb9525..a8b3c7b 100644
--- a/core/java/android/net/LinkProperties.aidl
+++ b/core/java/android/net/LinkProperties.aidl
@@ -17,4 +17,4 @@
package android.net;
-parcelable LinkProperties;
+@JavaOnlyStableParcelable parcelable LinkProperties;
diff --git a/core/java/android/net/LinkPropertiesParcelable.aidl b/core/java/android/net/LinkPropertiesParcelable.aidl
deleted file mode 100644
index 6b52239..0000000
--- a/core/java/android/net/LinkPropertiesParcelable.aidl
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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 android.net;
-
-import android.net.IpPrefixParcelable;
-import android.net.LinkAddressParcelable;
-import android.net.ProxyInfoParcelable;
-import android.net.RouteInfoParcelable;
-
-parcelable LinkPropertiesParcelable {
- String ifaceName;
- LinkAddressParcelable[] linkAddresses;
- String[] dnses;
- String[] pcscfs;
- String[] validatedPrivateDnses;
- boolean usePrivateDns;
- String privateDnsServerName;
- String domains;
- RouteInfoParcelable[] routes;
- ProxyInfoParcelable httpProxy;
- int mtu;
- String tcpBufferSizes;
- IpPrefixParcelable nat64Prefix;
-}
\ No newline at end of file
diff --git a/core/java/android/net/Network.aidl b/core/java/android/net/Network.aidl
index 73ba1af..05622025b 100644
--- a/core/java/android/net/Network.aidl
+++ b/core/java/android/net/Network.aidl
@@ -17,4 +17,4 @@
package android.net;
-parcelable Network;
+@JavaOnlyStableParcelable parcelable Network;
diff --git a/core/java/android/net/NetworkParcelable.aidl b/core/java/android/net/NetworkParcelable.aidl
deleted file mode 100644
index c26352e..0000000
--- a/core/java/android/net/NetworkParcelable.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
-**
-** 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 android.net;
-
-parcelable NetworkParcelable {
- long networkHandle;
-}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index d42fce3..ae421a4 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -40,6 +40,7 @@
import android.util.BackupUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.io.ByteArrayOutputStream;
@@ -89,10 +90,22 @@
private static boolean sForceAllNetworkTypes = false;
+ /**
+ * Results in matching against all mobile network types.
+ *
+ * <p>See {@link #matchesMobile} and {@link matchesMobileWildcard}.
+ */
+ @VisibleForTesting
public static void forceAllNetworkTypes() {
sForceAllNetworkTypes = true;
}
+ /** Resets the affect of {@link #forceAllNetworkTypes}. */
+ @VisibleForTesting
+ public static void resetForceAllNetworkTypes() {
+ sForceAllNetworkTypes = false;
+ }
+
/**
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
* the given IMSI.
diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java
index 2380e86..9d4727a 100644
--- a/core/java/android/net/ParseException.java
+++ b/core/java/android/net/ParseException.java
@@ -16,15 +16,22 @@
package android.net;
+import android.annotation.NonNull;
+
/**
- * Thrown when parsing a URL fails.
+ * Thrown when parsing failed.
*/
// See non-public class {@link WebAddress}.
public class ParseException extends RuntimeException {
public String response;
- ParseException(String response) {
+ public ParseException(@NonNull String response) {
super(response);
this.response = response;
}
+
+ public ParseException(@NonNull String response, @NonNull Throwable cause) {
+ super(response, cause);
+ this.response = response;
+ }
}
diff --git a/core/java/android/net/ProvisioningConfigurationParcelable.aidl b/core/java/android/net/ProvisioningConfigurationParcelable.aidl
index 2a144f2..5b46d7f 100644
--- a/core/java/android/net/ProvisioningConfigurationParcelable.aidl
+++ b/core/java/android/net/ProvisioningConfigurationParcelable.aidl
@@ -19,7 +19,7 @@
import android.net.ApfCapabilitiesParcelable;
import android.net.InitialConfigurationParcelable;
-import android.net.NetworkParcelable;
+import android.net.Network;
import android.net.StaticIpConfigurationParcelable;
parcelable ProvisioningConfigurationParcelable {
@@ -33,6 +33,6 @@
ApfCapabilitiesParcelable apfCapabilities;
int provisioningTimeoutMs;
int ipv6AddrGenMode;
- NetworkParcelable network;
+ Network network;
String displayName;
}
diff --git a/core/java/android/net/ProxyInfo.aidl b/core/java/android/net/ProxyInfo.aidl
index 2c91960..a5d0c12 100644
--- a/core/java/android/net/ProxyInfo.aidl
+++ b/core/java/android/net/ProxyInfo.aidl
@@ -17,5 +17,5 @@
package android.net;
-parcelable ProxyInfo;
+@JavaOnlyStableParcelable parcelable ProxyInfo;
diff --git a/core/java/android/net/RouteInfo.aidl b/core/java/android/net/RouteInfo.aidl
index 2296a57..7af9fda 100644
--- a/core/java/android/net/RouteInfo.aidl
+++ b/core/java/android/net/RouteInfo.aidl
@@ -16,4 +16,4 @@
package android.net;
-parcelable RouteInfo;
+@JavaOnlyStableParcelable parcelable RouteInfo;
diff --git a/core/java/android/net/RouteInfoParcelable.aidl b/core/java/android/net/RouteInfoParcelable.aidl
deleted file mode 100644
index 15bcdcf..0000000
--- a/core/java/android/net/RouteInfoParcelable.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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 android.net;
-
-import android.net.IpPrefixParcelable;
-
-parcelable RouteInfoParcelable {
- IpPrefixParcelable destination;
- String gatewayAddr;
- String ifaceName;
- int type;
-}
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 8b264ee..e253105 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -16,6 +16,8 @@
package android.net;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -53,22 +55,26 @@
public final class StaticIpConfiguration implements Parcelable {
/** @hide */
@UnsupportedAppUsage
+ @Nullable
public LinkAddress ipAddress;
/** @hide */
@UnsupportedAppUsage
+ @Nullable
public InetAddress gateway;
/** @hide */
@UnsupportedAppUsage
+ @NonNull
public final ArrayList<InetAddress> dnsServers;
/** @hide */
@UnsupportedAppUsage
+ @Nullable
public String domains;
public StaticIpConfiguration() {
dnsServers = new ArrayList<InetAddress>();
}
- public StaticIpConfiguration(StaticIpConfiguration source) {
+ public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
this();
if (source != null) {
// All of these except dnsServers are immutable, so no need to make copies.
@@ -86,38 +92,38 @@
domains = null;
}
- public LinkAddress getIpAddress() {
+ public @Nullable LinkAddress getIpAddress() {
return ipAddress;
}
- public void setIpAddress(LinkAddress ipAddress) {
+ public void setIpAddress(@Nullable LinkAddress ipAddress) {
this.ipAddress = ipAddress;
}
- public InetAddress getGateway() {
+ public @Nullable InetAddress getGateway() {
return gateway;
}
- public void setGateway(InetAddress gateway) {
+ public void setGateway(@Nullable InetAddress gateway) {
this.gateway = gateway;
}
- public List<InetAddress> getDnsServers() {
+ public @NonNull List<InetAddress> getDnsServers() {
return dnsServers;
}
- public String getDomains() {
+ public @Nullable String getDomains() {
return domains;
}
- public void setDomains(String newDomains) {
+ public void setDomains(@Nullable String newDomains) {
domains = newDomains;
}
/**
* Add a DNS server to this configuration.
*/
- public void addDnsServer(InetAddress server) {
+ public void addDnsServer(@NonNull InetAddress server) {
dnsServers.add(server);
}
@@ -128,7 +134,7 @@
* route to the gateway as well. This configuration is arguably invalid, but it used to work
* in K and earlier, and other OSes appear to accept it.
*/
- public List<RouteInfo> getRoutes(String iface) {
+ public @NonNull List<RouteInfo> getRoutes(String iface) {
List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
if (ipAddress != null) {
RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
@@ -150,7 +156,7 @@
* IPv6 configuration) will not be included.
* @hide
*/
- public LinkProperties toLinkProperties(String iface) {
+ public @NonNull LinkProperties toLinkProperties(String iface) {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(iface);
if (ipAddress != null) {
diff --git a/core/java/android/net/StaticIpConfigurationParcelable.aidl b/core/java/android/net/StaticIpConfigurationParcelable.aidl
index 45dc021..6fffb42 100644
--- a/core/java/android/net/StaticIpConfigurationParcelable.aidl
+++ b/core/java/android/net/StaticIpConfigurationParcelable.aidl
@@ -17,10 +17,10 @@
package android.net;
-import android.net.LinkAddressParcelable;
+import android.net.LinkAddress;
parcelable StaticIpConfigurationParcelable {
- LinkAddressParcelable ipAddress;
+ LinkAddress ipAddress;
String gateway;
String[] dnsServers;
String domains;
diff --git a/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl b/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
index 7329c63..d66b6ae 100644
--- a/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
+++ b/core/java/android/net/TcpKeepalivePacketDataParcelable.aidl
@@ -23,4 +23,6 @@
int dstPort;
int seq;
int ack;
+ int rcvWnd;
+ int rcvWndScale;
}
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index d4a4cf4..e56f059 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -19,14 +19,17 @@
import static android.os.UserHandle.PER_USER_RANGE;
import android.os.Parcel;
+import android.os.Parcelable;
/**
* An inclusive range of UIDs.
*
* @hide
*/
-public final class UidRange extends UidRangeParcel {
- private UidRange() {}
+public final class UidRange implements Parcelable {
+ public final int start;
+ public final int stop;
+
public UidRange(int startUid, int stopUid) {
if (startUid < 0) throw new IllegalArgumentException("Invalid start UID.");
if (stopUid < 0) throw new IllegalArgumentException("Invalid stop UID.");
@@ -86,18 +89,28 @@
return start + "-" + stop;
}
- /**
- * DO NOT override "writeToParcel" and "readFromParcel" in this class.
- * The parceling code is autogenerated by the superclass.
- */
+ // Implement the Parcelable interface
+ // TODO: Consider making this class no longer parcelable, since all users are likely in the
+ // system server.
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(start);
+ dest.writeInt(stop);
+ }
public static final @android.annotation.NonNull Creator<UidRange> CREATOR =
new Creator<UidRange>() {
@Override
public UidRange createFromParcel(Parcel in) {
- UidRange obj = new UidRange();
- obj.readFromParcel(in);
- return obj;
+ int start = in.readInt();
+ int stop = in.readInt();
+
+ return new UidRange(start, stop);
}
@Override
public UidRange[] newArray(int size) {
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 870d8b1..ea245a4 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -27,6 +27,8 @@
import android.app.Activity;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
@@ -48,6 +50,7 @@
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* VpnService is a base class for applications to extend and build their
@@ -138,7 +141,7 @@
* provides users with the ability to set it as always-on, so that VPN connection is
* persisted after device reboot and app upgrade. Always-on VPN can also be enabled by device
* owner and profile owner apps through
- * {@link android.app.admin.DevicePolicyManager#setAlwaysOnVpnPackage}.
+ * {@link DevicePolicyManager#setAlwaysOnVpnPackage}.
*
* <p>VPN apps not supporting this feature should opt out by adding this meta-data field to the
* {@code VpnService} component of {@code AndroidManifest.xml}. In case there is more than one
@@ -370,7 +373,10 @@
}
/**
- * Returns whether the service is running in always-on VPN mode.
+ * Returns whether the service is running in always-on VPN mode. In this mode the system ensures
+ * that the service is always running by restarting it when necessary, e.g. after reboot.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
public final boolean isAlwaysOn() {
try {
@@ -381,8 +387,11 @@
}
/**
- * Returns whether the service is running in always-on VPN mode blocking connections without
- * VPN.
+ * Returns whether the service is running in always-on VPN lockdown mode. In this mode the
+ * system ensures that the service is always running and that the apps aren't allowed to bypass
+ * the VPN.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)
*/
public final boolean isLockdownEnabled() {
try {
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index e09fa8f..d6023d7 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,17 +19,20 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.internal.R;
/**
* APF program support capabilities.
*
+ * This class is immutable.
* @hide
*/
@SystemApi
@TestApi
-public class ApfCapabilities {
+public final class ApfCapabilities implements Parcelable {
/**
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
* packet filtering using APF programs.
@@ -53,6 +56,37 @@
this.apfPacketFormat = apfPacketFormat;
}
+ private ApfCapabilities(Parcel in) {
+ apfVersionSupported = in.readInt();
+ maximumApfProgramSize = in.readInt();
+ apfPacketFormat = in.readInt();
+ }
+
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(apfVersionSupported);
+ dest.writeInt(maximumApfProgramSize);
+ dest.writeInt(apfPacketFormat);
+ }
+
+ public static final Creator<ApfCapabilities> CREATOR = new Creator<ApfCapabilities>() {
+ @Override
+ public ApfCapabilities createFromParcel(Parcel in) {
+ return new ApfCapabilities(in);
+ }
+
+ @Override
+ public ApfCapabilities[] newArray(int size) {
+ return new ApfCapabilities[size];
+ }
+ };
+
@Override
public String toString() {
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
index 3930344..a1d3de2 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -16,6 +16,7 @@
package android.net.captiveportal;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -39,14 +40,18 @@
*/
public static final int PARTIAL_CODE = -1;
+ @NonNull
public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE);
+ @NonNull
public static final CaptivePortalProbeResult SUCCESS =
new CaptivePortalProbeResult(SUCCESS_CODE);
public static final CaptivePortalProbeResult PARTIAL =
new CaptivePortalProbeResult(PARTIAL_CODE);
private final int mHttpResponseCode; // HTTP response code returned from Internet probe.
+ @Nullable
public final String redirectUrl; // Redirect destination returned from Internet probe.
+ @Nullable
public final String detectUrl; // URL where a 204 response code indicates
// captive portal has been appeased.
@Nullable
@@ -56,12 +61,13 @@
this(httpResponseCode, null, null);
}
- public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl) {
+ public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
+ @Nullable String detectUrl) {
this(httpResponseCode, redirectUrl, detectUrl, null);
}
- public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl,
- CaptivePortalProbeSpec probeSpec) {
+ public CaptivePortalProbeResult(int httpResponseCode, @Nullable String redirectUrl,
+ @Nullable String detectUrl, @Nullable CaptivePortalProbeSpec probeSpec) {
mHttpResponseCode = httpResponseCode;
this.redirectUrl = redirectUrl;
this.detectUrl = detectUrl;
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
index 7ad4ecf..6c6a16c 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -19,6 +19,8 @@
import static android.net.captiveportal.CaptivePortalProbeResult.PORTAL_CODE;
import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -48,9 +50,10 @@
private final String mEncodedSpec;
private final URL mUrl;
- CaptivePortalProbeSpec(String encodedSpec, URL url) {
- mEncodedSpec = encodedSpec;
- mUrl = url;
+ CaptivePortalProbeSpec(@NonNull String encodedSpec, @NonNull URL url)
+ throws NullPointerException {
+ mEncodedSpec = checkNotNull(encodedSpec);
+ mUrl = checkNotNull(url);
}
/**
@@ -64,7 +67,7 @@
*/
@VisibleForTesting
@NonNull
- public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException,
+ public static CaptivePortalProbeSpec parseSpec(@NonNull String spec) throws ParseException,
MalformedURLException {
if (TextUtils.isEmpty(spec)) {
throw new ParseException("Empty probe spec", 0 /* errorOffset */);
@@ -84,7 +87,8 @@
}
@Nullable
- private static Pattern parsePatternIfNonEmpty(String pattern, int pos) throws ParseException {
+ private static Pattern parsePatternIfNonEmpty(@Nullable String pattern, int pos)
+ throws ParseException {
if (TextUtils.isEmpty(pattern)) {
return null;
}
@@ -120,8 +124,9 @@
* <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}.
* <p>This method does not throw but ignores any entry that could not be parsed.
*/
+ @NonNull
public static Collection<CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(
- String settingsVal) {
+ @NonNull String settingsVal) {
List<CaptivePortalProbeSpec> specs = new ArrayList<>();
if (settingsVal != null) {
for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
@@ -142,12 +147,15 @@
/**
* Get the probe result from HTTP status and location header.
*/
+ @NonNull
public abstract CaptivePortalProbeResult getResult(int status, @Nullable String locationHeader);
+ @NonNull
public String getEncodedSpec() {
return mEncodedSpec;
}
+ @NonNull
public URL getUrl() {
return mUrl;
}
diff --git a/core/java/android/net/ip/IIpClient.aidl b/core/java/android/net/ip/IIpClient.aidl
index a4a80e1..b834e45 100644
--- a/core/java/android/net/ip/IIpClient.aidl
+++ b/core/java/android/net/ip/IIpClient.aidl
@@ -15,7 +15,7 @@
*/
package android.net.ip;
-import android.net.ProxyInfoParcelable;
+import android.net.ProxyInfo;
import android.net.ProvisioningConfigurationParcelable;
import android.net.TcpKeepalivePacketDataParcelable;
@@ -28,7 +28,7 @@
void startProvisioning(in ProvisioningConfigurationParcelable req);
void stop();
void setTcpBufferSizes(in String tcpBufferSizes);
- void setHttpProxy(in ProxyInfoParcelable proxyInfo);
+ void setHttpProxy(in ProxyInfo proxyInfo);
void setMulticastFilter(boolean enabled);
void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt);
void removeKeepalivePacketFilter(int slot);
diff --git a/core/java/android/net/ip/IIpClientCallbacks.aidl b/core/java/android/net/ip/IIpClientCallbacks.aidl
index f077e3b..3681416 100644
--- a/core/java/android/net/ip/IIpClientCallbacks.aidl
+++ b/core/java/android/net/ip/IIpClientCallbacks.aidl
@@ -15,7 +15,7 @@
*/
package android.net.ip;
-import android.net.LinkPropertiesParcelable;
+import android.net.LinkProperties;
import android.net.ip.IIpClient;
import android.net.DhcpResultsParcelable;
@@ -34,11 +34,11 @@
// null or not.
void onNewDhcpResults(in DhcpResultsParcelable dhcpResults);
- void onProvisioningSuccess(in LinkPropertiesParcelable newLp);
- void onProvisioningFailure(in LinkPropertiesParcelable newLp);
+ void onProvisioningSuccess(in LinkProperties newLp);
+ void onProvisioningFailure(in LinkProperties newLp);
// Invoked on LinkProperties changes.
- void onLinkPropertiesChange(in LinkPropertiesParcelable newLp);
+ void onLinkPropertiesChange(in LinkProperties newLp);
// Called when the internal IpReachabilityMonitor (if enabled) has
// detected the loss of a critical number of required neighbors.
diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java
index b30d8cb..2bd4378 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -17,6 +17,7 @@
package android.net.metrics;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -95,7 +96,7 @@
/**
* Utility to create an instance of {@link ApfProgramEvent}.
*/
- public static class Builder {
+ public static final class Builder {
private long mLifetime;
private long mActualLifetime;
private int mFilteredRas;
@@ -106,6 +107,7 @@
/**
* Set the maximum computed lifetime of the program in seconds.
*/
+ @NonNull
public Builder setLifetime(long lifetime) {
mLifetime = lifetime;
return this;
@@ -114,6 +116,7 @@
/**
* Set the effective program lifetime in seconds.
*/
+ @NonNull
public Builder setActualLifetime(long lifetime) {
mActualLifetime = lifetime;
return this;
@@ -122,6 +125,7 @@
/**
* Set the number of RAs filtered by the APF program.
*/
+ @NonNull
public Builder setFilteredRas(int filteredRas) {
mFilteredRas = filteredRas;
return this;
@@ -130,6 +134,7 @@
/**
* Set the total number of current RAs at generation time.
*/
+ @NonNull
public Builder setCurrentRas(int currentRas) {
mCurrentRas = currentRas;
return this;
@@ -138,6 +143,7 @@
/**
* Set the length of the APF program in bytes.
*/
+ @NonNull
public Builder setProgramLength(int programLength) {
mProgramLength = programLength;
return this;
@@ -146,6 +152,7 @@
/**
* Set the flags describing what an Apf program filters.
*/
+ @NonNull
public Builder setFlags(boolean hasIPv4, boolean multicastFilterOn) {
mFlags = flagsFor(hasIPv4, multicastFilterOn);
return this;
@@ -154,6 +161,7 @@
/**
* Build a new {@link ApfProgramEvent}.
*/
+ @NonNull
public ApfProgramEvent build() {
return new ApfProgramEvent(mLifetime, mActualLifetime, mFilteredRas, mCurrentRas,
mProgramLength, mFlags);
diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java
index e1c8888..6c3b7af 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -125,7 +126,7 @@
*/
@SystemApi
@TestApi
- public static class Builder {
+ public static final class Builder {
private long mDurationMs;
private int mReceivedRas;
private int mMatchingRas;
@@ -140,6 +141,7 @@
/**
* Set the time interval in milliseconds these statistics covers.
*/
+ @NonNull
public Builder setDurationMs(long durationMs) {
mDurationMs = durationMs;
return this;
@@ -148,6 +150,7 @@
/**
* Set the number of received RAs.
*/
+ @NonNull
public Builder setReceivedRas(int receivedRas) {
mReceivedRas = receivedRas;
return this;
@@ -156,6 +159,7 @@
/**
* Set the number of received RAs matching a known RA.
*/
+ @NonNull
public Builder setMatchingRas(int matchingRas) {
mMatchingRas = matchingRas;
return this;
@@ -164,6 +168,7 @@
/**
* Set the number of received RAs ignored due to the MAX_RAS limit.
*/
+ @NonNull
public Builder setDroppedRas(int droppedRas) {
mDroppedRas = droppedRas;
return this;
@@ -172,6 +177,7 @@
/**
* Set the number of received RAs with a minimum lifetime of 0.
*/
+ @NonNull
public Builder setZeroLifetimeRas(int zeroLifetimeRas) {
mZeroLifetimeRas = zeroLifetimeRas;
return this;
@@ -180,6 +186,7 @@
/**
* Set the number of received RAs that could not be parsed.
*/
+ @NonNull
public Builder setParseErrors(int parseErrors) {
mParseErrors = parseErrors;
return this;
@@ -188,6 +195,7 @@
/**
* Set the number of APF program updates from receiving RAs.
*/
+ @NonNull
public Builder setProgramUpdates(int programUpdates) {
mProgramUpdates = programUpdates;
return this;
@@ -196,6 +204,7 @@
/**
* Set the total number of APF program updates.
*/
+ @NonNull
public Builder setProgramUpdatesAll(int programUpdatesAll) {
mProgramUpdatesAll = programUpdatesAll;
return this;
@@ -204,6 +213,7 @@
/**
* Set the number of APF program updates from allowing multicast traffic.
*/
+ @NonNull
public Builder setProgramUpdatesAllowingMulticast(int programUpdatesAllowingMulticast) {
mProgramUpdatesAllowingMulticast = programUpdatesAllowingMulticast;
return this;
@@ -212,6 +222,7 @@
/**
* Set the maximum APF program size advertised by hardware.
*/
+ @NonNull
public Builder setMaxProgramSize(int maxProgramSize) {
mMaxProgramSize = maxProgramSize;
return this;
@@ -220,6 +231,7 @@
/**
* Create a new {@link ApfStats}.
*/
+ @NonNull
public ApfStats build() {
return new ApfStats(mDurationMs, mReceivedRas, mMatchingRas, mDroppedRas,
mZeroLifetimeRas, mParseErrors, mProgramUpdates, mProgramUpdatesAll,
diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java
index e4faea9..a3d0a20 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
@@ -51,13 +52,14 @@
/**
* Utility to create an instance of {@link ApfProgramEvent}.
*/
- public static class Builder {
+ public static final class Builder {
private String mMsg;
private int mDurationMs;
/**
* Set the message of the event.
*/
+ @NonNull
public Builder setMsg(String msg) {
mMsg = msg;
return this;
@@ -66,6 +68,7 @@
/**
* Set the duration of the event in milliseconds.
*/
+ @NonNull
public Builder setDurationMs(int durationMs) {
mDurationMs = durationMs;
return this;
@@ -74,6 +77,7 @@
/**
* Create a new {@link DhcpClientEvent}.
*/
+ @NonNull
public DhcpClientEvent build() {
return new DhcpClientEvent(mMsg, mDurationMs);
}
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 91318a2..652ce5d 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -37,26 +37,26 @@
public static final int DHCP_ERROR = 4;
public static final int MISC_ERROR = 5;
- public static final int L2_TOO_SHORT = makeErrorCode(L2_ERROR, 1);
- public static final int L2_WRONG_ETH_TYPE = makeErrorCode(L2_ERROR, 2);
+ public static final int L2_TOO_SHORT = (L2_ERROR << 24) | (1 << 16);
+ public static final int L2_WRONG_ETH_TYPE = (L2_ERROR << 24) | (2 << 16);
- public static final int L3_TOO_SHORT = makeErrorCode(L3_ERROR, 1);
- public static final int L3_NOT_IPV4 = makeErrorCode(L3_ERROR, 2);
- public static final int L3_INVALID_IP = makeErrorCode(L3_ERROR, 3);
+ public static final int L3_TOO_SHORT = (L3_ERROR << 24) | (1 << 16);
+ public static final int L3_NOT_IPV4 = (L3_ERROR << 24) | (2 << 16);
+ public static final int L3_INVALID_IP = (L3_ERROR << 24) | (3 << 16);
- public static final int L4_NOT_UDP = makeErrorCode(L4_ERROR, 1);
- public static final int L4_WRONG_PORT = makeErrorCode(L4_ERROR, 2);
+ public static final int L4_NOT_UDP = (L4_ERROR << 24) | (1 << 16);
+ public static final int L4_WRONG_PORT = (L4_ERROR << 24) | (2 << 16);
- public static final int BOOTP_TOO_SHORT = makeErrorCode(DHCP_ERROR, 1);
- public static final int DHCP_BAD_MAGIC_COOKIE = makeErrorCode(DHCP_ERROR, 2);
- public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
- public static final int DHCP_NO_MSG_TYPE = makeErrorCode(DHCP_ERROR, 4);
- public static final int DHCP_UNKNOWN_MSG_TYPE = makeErrorCode(DHCP_ERROR, 5);
- public static final int DHCP_NO_COOKIE = makeErrorCode(DHCP_ERROR, 6);
+ public static final int BOOTP_TOO_SHORT = (DHCP_ERROR << 24) | (1 << 16);
+ public static final int DHCP_BAD_MAGIC_COOKIE = (DHCP_ERROR << 24) | (2 << 16);
+ public static final int DHCP_INVALID_OPTION_LENGTH = (DHCP_ERROR << 24) | (3 << 16);
+ public static final int DHCP_NO_MSG_TYPE = (DHCP_ERROR << 24) | (4 << 16);
+ public static final int DHCP_UNKNOWN_MSG_TYPE = (DHCP_ERROR << 24) | (5 << 16);
+ public static final int DHCP_NO_COOKIE = (DHCP_ERROR << 24) | (6 << 16);
- public static final int BUFFER_UNDERFLOW = makeErrorCode(MISC_ERROR, 1);
- public static final int RECEIVE_ERROR = makeErrorCode(MISC_ERROR, 2);
- public static final int PARSING_ERROR = makeErrorCode(MISC_ERROR, 3);
+ public static final int BUFFER_UNDERFLOW = (MISC_ERROR << 24) | (1 << 16);
+ public static final int RECEIVE_ERROR = (MISC_ERROR << 24) | (2 << 16);
+ public static final int PARSING_ERROR = (MISC_ERROR << 24) | (3 << 16);
// error code byte format (MSB to LSB):
// byte 0: error type
@@ -102,10 +102,6 @@
return (0xFFFF0000 & errorCode) | (0xFF & option);
}
- private static int makeErrorCode(int type, int subtype) {
- return (type << 24) | ((0xFF & subtype) << 16);
- }
-
@Override
public String toString() {
return String.format("DhcpErrorEvent(%s)", Decoder.constants.get(errorCode));
diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java
index 5b5a235..680c015 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -16,6 +16,7 @@
package android.net.metrics;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.net.ConnectivityMetricsEvent;
@@ -41,7 +42,7 @@
/** @hide */
public static final String SERVICE_NAME = "connmetrics";
-
+ @NonNull
private IIpConnectivityMetrics mService;
/**
@@ -57,7 +58,7 @@
/** @hide */
@VisibleForTesting
- public IpConnectivityLog(IIpConnectivityMetrics service) {
+ public IpConnectivityLog(@NonNull IIpConnectivityMetrics service) {
mService = service;
}
@@ -83,7 +84,7 @@
* @return true if the event was successfully logged.
* @hide
*/
- public boolean log(ConnectivityMetricsEvent ev) {
+ public boolean log(@NonNull ConnectivityMetricsEvent ev) {
if (!checkLoggerService()) {
if (DBG) {
Log.d(TAG, SERVICE_NAME + " service was not ready");
@@ -109,7 +110,7 @@
* @param data is a Parcelable instance representing the event.
* @return true if the event was successfully logged.
*/
- public boolean log(long timestamp, Event data) {
+ public boolean log(long timestamp, @NonNull Event data) {
ConnectivityMetricsEvent ev = makeEv(data);
ev.timestamp = timestamp;
return log(ev);
@@ -121,7 +122,7 @@
* @param data is a Parcelable instance representing the event.
* @return true if the event was successfully logged.
*/
- public boolean log(String ifname, Event data) {
+ public boolean log(@NonNull String ifname, @NonNull Event data) {
ConnectivityMetricsEvent ev = makeEv(data);
ev.ifname = ifname;
return log(ev);
@@ -135,7 +136,7 @@
* @param data is a Parcelable instance representing the event.
* @return true if the event was successfully logged.
*/
- public boolean log(Network network, int[] transports, Event data) {
+ public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) {
return log(network.netId, transports, data);
}
@@ -147,7 +148,7 @@
* @param data is a Parcelable instance representing the event.
* @return true if the event was successfully logged.
*/
- public boolean log(int netid, int[] transports, Event data) {
+ public boolean log(int netid, @NonNull int[] transports, @NonNull Event data) {
ConnectivityMetricsEvent ev = makeEv(data);
ev.netId = netid;
ev.transports = BitUtils.packBits(transports);
@@ -159,7 +160,7 @@
* @param data is a Parcelable instance representing the event.
* @return true if the event was successfully logged.
*/
- public boolean log(Event data) {
+ public boolean log(@NonNull Event data) {
return log(makeEv(data));
}
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
index 052758d..45b665d 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -17,6 +17,7 @@
package android.net.metrics;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.os.Parcel;
@@ -81,7 +82,7 @@
/**
* Utility to create an instance of {@link ValidationProbeEvent}.
*/
- public static class Builder {
+ public static final class Builder {
private long mDurationMs;
private int mProbeType;
private int mReturnCode;
@@ -89,6 +90,7 @@
/**
* Set the duration of the probe in milliseconds.
*/
+ @NonNull
public Builder setDurationMs(long durationMs) {
mDurationMs = durationMs;
return this;
@@ -97,6 +99,7 @@
/**
* Set the probe type based on whether it was the first validation.
*/
+ @NonNull
public Builder setProbeType(int probeType, boolean firstValidation) {
mProbeType = makeProbeType(probeType, firstValidation);
return this;
@@ -105,6 +108,7 @@
/**
* Set the return code of the probe.
*/
+ @NonNull
public Builder setReturnCode(int returnCode) {
mReturnCode = returnCode;
return this;
@@ -113,6 +117,7 @@
/**
* Create a new {@link ValidationProbeEvent}.
*/
+ @NonNull
public ValidationProbeEvent build() {
return new ValidationProbeEvent(mDurationMs, mProbeType, mReturnCode);
}
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 5827f9e..6f8aece 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -45,7 +45,7 @@
*/
@SystemApi
@TestApi
-public class SocketUtils {
+public final class SocketUtils {
/**
* Create a raw datagram socket that is bound to an interface.
*
@@ -63,6 +63,7 @@
/**
* Make a socket address to communicate with netlink.
*/
+ @NonNull
public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) {
return new NetlinkSocketAddress(portId, groupsMask);
}
@@ -70,13 +71,15 @@
/**
* Make socket address that packet sockets can bind to.
*/
- public static SocketAddress makePacketSocketAddress(short protocol, int ifIndex) {
- return new PacketSocketAddress(protocol, ifIndex);
+ @NonNull
+ public static SocketAddress makePacketSocketAddress(int protocol, int ifIndex) {
+ return new PacketSocketAddress((short) protocol, ifIndex);
}
/**
* Make a socket address that packet socket can send packets to.
*/
+ @NonNull
public static SocketAddress makePacketSocketAddress(int ifIndex, @NonNull byte[] hwAddr) {
return new PacketSocketAddress(ifIndex, hwAddr);
}
diff --git a/core/java/android/os/AsyncResult.java b/core/java/android/os/AsyncResult.java
index 5bad09d..58a2701 100644
--- a/core/java/android/os/AsyncResult.java
+++ b/core/java/android/os/AsyncResult.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.os.Message;
/** @hide */
@@ -25,13 +26,17 @@
/*************************** Instance Variables **************************/
// Expect either exception or result to be null
+ @UnsupportedAppUsage
public Object userObj;
+ @UnsupportedAppUsage
public Throwable exception;
+ @UnsupportedAppUsage
public Object result;
/***************************** Class Methods *****************************/
/** Saves and sets m.obj */
+ @UnsupportedAppUsage
public static AsyncResult
forMessage(Message m, Object r, Throwable ex)
{
@@ -45,6 +50,7 @@
}
/** Saves and sets m.obj */
+ @UnsupportedAppUsage
public static AsyncResult
forMessage(Message m)
{
@@ -58,6 +64,7 @@
}
/** please note, this sets m.obj to be this */
+ @UnsupportedAppUsage
public
AsyncResult (Object uo, Object r, Throwable ex)
{
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index a851e04..d259f38 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -18,6 +18,7 @@
import android.annotation.MainThread;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.annotation.WorkerThread;
import java.util.ArrayDeque;
@@ -259,15 +260,20 @@
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
+ @UnsupportedAppUsage
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
private static InternalHandler sHandler;
+ @UnsupportedAppUsage
private final WorkerRunnable<Params, Result> mWorker;
+ @UnsupportedAppUsage
private final FutureTask<Result> mFuture;
+ @UnsupportedAppUsage
private volatile Status mStatus = Status.PENDING;
private final AtomicBoolean mCancelled = new AtomicBoolean();
+ @UnsupportedAppUsage
private final AtomicBoolean mTaskInvoked = new AtomicBoolean();
private final Handler mHandler;
@@ -331,6 +337,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 3d4c00c..7f63f8f 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Log;
import android.util.MathUtils;
@@ -82,6 +83,7 @@
// Invariant - exactly one of mMap / mParcelledData will be null
// (except inside a call to unparcel)
+ @UnsupportedAppUsage
ArrayMap<String, Object> mMap = null;
/*
@@ -89,6 +91,7 @@
* data are stored as a Parcel containing a Bundle. When the data
* are unparcelled, mParcelledData willbe set to null.
*/
+ @UnsupportedAppUsage
Parcel mParcelledData = null;
/**
@@ -225,6 +228,7 @@
* If the underlying data are stored as a Parcel, unparcel them
* using the currently assigned class loader.
*/
+ @UnsupportedAppUsage
/* package */ void unparcel() {
synchronized (this) {
final Parcel source = mParcelledData;
@@ -311,6 +315,7 @@
/**
* @hide
*/
+ @UnsupportedAppUsage
public boolean isParcelled() {
return mParcelledData != null;
}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 6639f0f..5ced86c 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -21,6 +21,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
import android.hardware.health.V1_0.Constants;
@@ -112,6 +113,7 @@
* to the device.
* {@hide}
*/
+ @UnsupportedAppUsage
public static final String EXTRA_INVALID_CHARGER = "invalid_charger";
/**
@@ -119,6 +121,7 @@
* Int value set to the maximum charging current supported by the charger in micro amperes.
* {@hide}
*/
+ @UnsupportedAppUsage
public static final String EXTRA_MAX_CHARGING_CURRENT = "max_charging_current";
/**
@@ -126,6 +129,7 @@
* Int value set to the maximum charging voltage supported by the charger in micro volts.
* {@hide}
*/
+ @UnsupportedAppUsage
public static final String EXTRA_MAX_CHARGING_VOLTAGE = "max_charging_voltage";
/**
@@ -133,6 +137,7 @@
* integer containing the charge counter present in the battery.
* {@hide}
*/
+ @UnsupportedAppUsage
public static final String EXTRA_CHARGE_COUNTER = "charge_counter";
/**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e4277e4..b64fe00 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION;
+import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.job.JobParameters;
import android.content.Context;
@@ -74,6 +75,7 @@
/**
* A constant indicating a partial wake lock timer.
*/
+ @UnsupportedAppUsage
public static final int WAKE_TYPE_PARTIAL = 0;
/**
@@ -198,12 +200,21 @@
/**
* Include only the current run in the stats.
+ *
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, only {@link #STATS_SINCE_CHARGED}
+ * is supported.
*/
+ @UnsupportedAppUsage
+ @Deprecated
public static final int STATS_CURRENT = 1;
/**
* Include only the run since the last time the device was unplugged in the stats.
+ *
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, only {@link #STATS_SINCE_CHARGED}
+ * is supported.
*/
+ @Deprecated
public static final int STATS_SINCE_UNPLUGGED = 2;
// NOTE: Update this list if you add/change any stats above.
@@ -252,8 +263,10 @@
* - Ambient display properly output in data dump.
* New in version 33:
* - Fixed bug in min learned capacity updating process.
+ * New in version 34:
+ * - Deprecated STATS_SINCE_UNPLUGGED and STATS_CURRENT.
*/
- static final int CHECKIN_VERSION = 33;
+ static final int CHECKIN_VERSION = 34;
/**
* Old version, we hit 9 and ran out of room, need to remove.
@@ -396,6 +409,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
+ @UnsupportedAppUsage
public abstract int getCountLocked(int which);
/**
@@ -504,6 +518,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
*/
+ @UnsupportedAppUsage
public abstract int getCountLocked(int which);
/**
@@ -514,6 +529,7 @@
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT
* @return a time in microseconds
*/
+ @UnsupportedAppUsage
public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which);
/**
@@ -616,6 +632,7 @@
*
* @return a Map from Strings to Uid.Wakelock objects.
*/
+ @UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
/**
@@ -650,6 +667,7 @@
* The statistics associated with a particular wake lock.
*/
public static abstract class Wakelock {
+ @UnsupportedAppUsage
public abstract Timer getWakeTime(int type);
}
@@ -665,6 +683,7 @@
*
* @return a Map from Integer sensor ids to Uid.Sensor objects.
*/
+ @UnsupportedAppUsage
public abstract SparseArray<? extends Sensor> getSensorStats();
/**
@@ -677,6 +696,7 @@
*
* @return a Map from Strings to Uid.Proc objects.
*/
+ @UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Proc> getProcessStats();
/**
@@ -684,6 +704,7 @@
*
* @return a Map from Strings to Uid.Pkg objects.
*/
+ @UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
public abstract ControllerActivityCounter getWifiControllerActivity();
@@ -693,6 +714,7 @@
/**
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract int getUid();
public abstract void noteWifiRunningLocked(long elapsedRealtime);
@@ -707,8 +729,11 @@
public abstract void noteWifiMulticastDisabledLocked(long elapsedRealtime);
public abstract void noteActivityResumedLocked(long elapsedRealtime);
public abstract void noteActivityPausedLocked(long elapsedRealtime);
+ @UnsupportedAppUsage
public abstract long getWifiRunningTime(long elapsedRealtimeUs, int which);
+ @UnsupportedAppUsage
public abstract long getFullWifiLockTime(long elapsedRealtimeUs, int which);
+ @UnsupportedAppUsage
public abstract long getWifiScanTime(long elapsedRealtimeUs, int which);
public abstract int getWifiScanCount(int which);
/**
@@ -722,10 +747,14 @@
* Returns the timer keeping track of background wifi scans.
*/
public abstract Timer getWifiScanBackgroundTimer();
+ @UnsupportedAppUsage
public abstract long getWifiBatchedScanTime(int csphBin, long elapsedRealtimeUs, int which);
public abstract int getWifiBatchedScanCount(int csphBin, int which);
+ @UnsupportedAppUsage
public abstract long getWifiMulticastTime(long elapsedRealtimeUs, int which);
+ @UnsupportedAppUsage
public abstract Timer getAudioTurnedOnTimer();
+ @UnsupportedAppUsage
public abstract Timer getVideoTurnedOnTimer();
public abstract Timer getFlashlightTurnedOnTimer();
public abstract Timer getCameraTurnedOnTimer();
@@ -857,8 +886,10 @@
public abstract int getUserActivityCount(int type, int which);
public abstract boolean hasNetworkActivity();
+ @UnsupportedAppUsage
public abstract long getNetworkActivityBytes(int type, int which);
public abstract long getNetworkActivityPackets(int type, int which);
+ @UnsupportedAppUsage
public abstract long getMobileRadioActiveTime(int which);
public abstract int getMobileRadioActiveCount(int which);
@@ -918,10 +949,13 @@
* the sensor HAL, and therefore out of our control
*/
// Magic sensor number for the GPS.
+ @UnsupportedAppUsage
public static final int GPS = -10000;
+ @UnsupportedAppUsage
public abstract int getHandle();
+ @UnsupportedAppUsage
public abstract Timer getSensorTime();
/** Returns a Timer for sensor usage when app is in the background. */
@@ -943,8 +977,11 @@
public static final int TYPE_WAKE = 1;
public static final int TYPE_CPU = 2;
+ @UnsupportedAppUsage
public int type;
+ @UnsupportedAppUsage
public long overTime;
+ @UnsupportedAppUsage
public long usedTime;
}
@@ -958,6 +995,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract long getUserTime(int which);
/**
@@ -965,6 +1003,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract long getSystemTime(int which);
/**
@@ -972,6 +1011,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract int getStarts(int which);
/**
@@ -993,10 +1033,13 @@
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @return foreground cpu time in microseconds
*/
+ @UnsupportedAppUsage
public abstract long getForegroundTime(int which);
+ @UnsupportedAppUsage
public abstract int countExcessivePowers();
+ @UnsupportedAppUsage
public abstract ExcessivePower getExcessivePower(int i);
}
@@ -1010,11 +1053,13 @@
* package. The mapping keys are tag names for the alarms, the counter contains
* the number of times the alarm was triggered while on battery.
*/
+ @UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Counter> getWakeupAlarmStats();
/**
* Returns a mapping containing service statistics.
*/
+ @UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Serv> getServiceStats();
/**
@@ -1029,6 +1074,7 @@
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
* @return
*/
+ @UnsupportedAppUsage
public abstract long getStartTime(long batteryUptime, int which);
/**
@@ -1036,6 +1082,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract int getStarts(int which);
/**
@@ -1043,6 +1090,7 @@
*
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract int getLaunches(int which);
}
}
@@ -1505,8 +1553,10 @@
public HistoryItem next;
// The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
+ @UnsupportedAppUsage
public long time;
+ @UnsupportedAppUsage
public static final byte CMD_UPDATE = 0; // These can be written as deltas
public static final byte CMD_NULL = -1;
public static final byte CMD_START = 4;
@@ -1515,6 +1565,7 @@
public static final byte CMD_RESET = 7;
public static final byte CMD_SHUTDOWN = 8;
+ @UnsupportedAppUsage
public byte cmd = CMD_NULL;
/**
@@ -1524,12 +1575,17 @@
return cmd == CMD_UPDATE;
}
+ @UnsupportedAppUsage
public byte batteryLevel;
+ @UnsupportedAppUsage
public byte batteryStatus;
+ @UnsupportedAppUsage
public byte batteryHealth;
+ @UnsupportedAppUsage
public byte batteryPlugType;
public short batteryTemperature;
+ @UnsupportedAppUsage
public char batteryVoltage;
// The charge of the battery in micro-Ampere-hours.
@@ -1579,6 +1635,7 @@
public static final int SETTLE_TO_ZERO_STATES = 0xffff0000 & ~MOST_INTERESTING_STATES;
+ @UnsupportedAppUsage
public int states;
// Constants from WIFI_SUPPL_STATE_*
@@ -1614,6 +1671,7 @@
public static final int SETTLE_TO_ZERO_STATES2 = 0xffff0000 & ~MOST_INTERESTING_STATES2;
+ @UnsupportedAppUsage
public int states2;
// The wake lock that was acquired at this point.
@@ -1722,6 +1780,7 @@
public final HistoryTag localWakeReasonTag = new HistoryTag();
public final HistoryTag localEventTag = new HistoryTag();
+ @UnsupportedAppUsage
public HistoryItem() {
}
@@ -2023,6 +2082,7 @@
public abstract int getHistoryUsedSize();
+ @UnsupportedAppUsage
public abstract boolean startIteratingHistoryLocked();
public abstract int getHistoryStringPoolSize();
@@ -2033,6 +2093,7 @@
public abstract int getHistoryTagPoolUid(int index);
+ @UnsupportedAppUsage
public abstract boolean getNextHistoryLocked(HistoryItem out);
public abstract void finishIteratingHistoryLocked();
@@ -2059,6 +2120,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract long getScreenOnTime(long elapsedRealtimeUs, int which);
/**
@@ -2099,6 +2161,7 @@
"0", "1", "2", "3", "4"
};
+ @UnsupportedAppUsage
public static final int NUM_SCREEN_BRIGHTNESS_BINS = 5;
/**
@@ -2107,6 +2170,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract long getScreenBrightnessTime(int brightnessBin,
long elapsedRealtimeUs, int which);
@@ -2215,6 +2279,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract long getPhoneOnTime(long elapsedRealtimeUs, int which);
/**
@@ -2230,6 +2295,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract long getPhoneSignalStrengthTime(int strengthBin,
long elapsedRealtimeUs, int which);
@@ -2313,6 +2379,7 @@
"other"
};
+ @UnsupportedAppUsage
public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1;
/**
@@ -2475,6 +2542,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract long getWifiOnTime(long elapsedRealtimeUs, int which);
/**
@@ -2491,6 +2559,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public abstract long getGlobalWifiRunningTime(long elapsedRealtimeUs, int which);
public static final int WIFI_STATE_OFF = 0;
@@ -2696,6 +2765,7 @@
/**
* Returns a SparseArray containing the statistics for each uid.
*/
+ @UnsupportedAppUsage
public abstract SparseArray<? extends Uid> getUidStats();
/**
@@ -2703,6 +2773,7 @@
*
* @param curTime the amount of elapsed realtime in microseconds.
*/
+ @UnsupportedAppUsage
public abstract long getBatteryUptime(long curTime);
/**
@@ -2783,6 +2854,7 @@
* @param curTime the elapsed realtime in microseconds.
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract long computeBatteryUptime(long curTime, int which);
/**
@@ -2791,6 +2863,7 @@
* @param curTime the current elapsed realtime in microseconds.
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
*/
+ @UnsupportedAppUsage
public abstract long computeBatteryRealtime(long curTime, int which);
/**
@@ -2833,6 +2906,7 @@
*
* @param curTime The current elepsed realtime in microseconds.
*/
+ @UnsupportedAppUsage
public abstract long computeBatteryTimeRemaining(long curTime);
// The part of a step duration that is the actual time.
@@ -2967,6 +3041,7 @@
*
* @param curTime The current elepsed realtime in microseconds.
*/
+ @UnsupportedAppUsage
public abstract long computeChargeTimeRemaining(long curTime);
/**
@@ -3251,6 +3326,7 @@
* @param type type of data (e.g. "wakelock", "sensor", "process", "apk" , "process", "network")
* @param args type-dependent data arguments
*/
+ @UnsupportedAppUsage
private static final void dumpLine(PrintWriter pw, int uid, String category, String type,
Object... args ) {
dumpLineHeader(pw, uid, category, type);
@@ -3585,6 +3661,14 @@
*/
public final void dumpCheckinLocked(Context context, PrintWriter pw, int which, int reqUid,
boolean wifiOnly) {
+
+ if (which != BatteryStats.STATS_SINCE_CHARGED) {
+ dumpLine(pw, 0, STAT_NAMES[which], "err",
+ "ERROR: BatteryStats.dumpCheckin called for which type " + which
+ + " but only STATS_SINCE_CHARGED is supported.");
+ return;
+ }
+
final long rawUptime = SystemClock.uptimeMillis() * 1000;
final long rawRealtimeMs = SystemClock.elapsedRealtime();
final long rawRealtime = rawRealtimeMs * 1000;
@@ -3782,28 +3866,13 @@
multicastWakeLockTimeTotalMicros / 1000,
multicastWakeLockCountTotal);
- if (which == STATS_SINCE_UNPLUGGED) {
- dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
- getDischargeCurrentLevel());
- }
-
- if (which == STATS_SINCE_UNPLUGGED) {
- dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
- getDischargeStartLevel()-getDischargeCurrentLevel(),
- getDischargeStartLevel()-getDischargeCurrentLevel(),
- getDischargeAmountScreenOn(), getDischargeAmountScreenOff(),
- dischargeCount / 1000, dischargeScreenOffCount / 1000,
- getDischargeAmountScreenDoze(), dischargeScreenDozeCount / 1000,
- dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000);
- } else {
- dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
- getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
- getDischargeAmountScreenOnSinceCharge(),
- getDischargeAmountScreenOffSinceCharge(),
- dischargeCount / 1000, dischargeScreenOffCount / 1000,
- getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000,
- dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000);
- }
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
+ getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
+ getDischargeAmountScreenOnSinceCharge(),
+ getDischargeAmountScreenOffSinceCharge(),
+ dischargeCount / 1000, dischargeScreenOffCount / 1000,
+ getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000,
+ dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000);
if (reqUid < 0) {
final Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
@@ -4366,6 +4435,13 @@
@SuppressWarnings("unused")
public final void dumpLocked(Context context, PrintWriter pw, String prefix, final int which,
int reqUid, boolean wifiOnly) {
+
+ if (which != BatteryStats.STATS_SINCE_CHARGED) {
+ pw.println("ERROR: BatteryStats.dump called for which type " + which
+ + " but only STATS_SINCE_CHARGED is supported");
+ return;
+ }
+
final long rawUptime = SystemClock.uptimeMillis() * 1000;
final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
final long rawRealtimeMs = (rawRealtime + 500) / 1000;
@@ -4978,41 +5054,18 @@
pw.println();
- if (which == STATS_SINCE_UNPLUGGED) {
- if (getIsOnBattery()) {
- pw.print(prefix); pw.println(" Device is currently unplugged");
- pw.print(prefix); pw.print(" Discharge cycle start level: ");
- pw.println(getDischargeStartLevel());
- pw.print(prefix); pw.print(" Discharge cycle current level: ");
- pw.println(getDischargeCurrentLevel());
- } else {
- pw.print(prefix); pw.println(" Device is currently plugged into power");
- pw.print(prefix); pw.print(" Last discharge cycle start level: ");
- pw.println(getDischargeStartLevel());
- pw.print(prefix); pw.print(" Last discharge cycle end level: ");
- pw.println(getDischargeCurrentLevel());
- }
- pw.print(prefix); pw.print(" Amount discharged while screen on: ");
- pw.println(getDischargeAmountScreenOn());
- pw.print(prefix); pw.print(" Amount discharged while screen off: ");
- pw.println(getDischargeAmountScreenOff());
- pw.print(prefix); pw.print(" Amount discharged while screen doze: ");
- pw.println(getDischargeAmountScreenDoze());
- pw.println(" ");
- } else {
- pw.print(prefix); pw.println(" Device battery use since last full charge");
- pw.print(prefix); pw.print(" Amount discharged (lower bound): ");
- pw.println(getLowDischargeAmountSinceCharge());
- pw.print(prefix); pw.print(" Amount discharged (upper bound): ");
- pw.println(getHighDischargeAmountSinceCharge());
- pw.print(prefix); pw.print(" Amount discharged while screen on: ");
- pw.println(getDischargeAmountScreenOnSinceCharge());
- pw.print(prefix); pw.print(" Amount discharged while screen off: ");
- pw.println(getDischargeAmountScreenOffSinceCharge());
- pw.print(prefix); pw.print(" Amount discharged while screen doze: ");
- pw.println(getDischargeAmountScreenDozeSinceCharge());
- pw.println();
- }
+ pw.print(prefix); pw.println(" Device battery use since last full charge");
+ pw.print(prefix); pw.print(" Amount discharged (lower bound): ");
+ pw.println(getLowDischargeAmountSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged (upper bound): ");
+ pw.println(getHighDischargeAmountSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged while screen on: ");
+ pw.println(getDischargeAmountScreenOnSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged while screen off: ");
+ pw.println(getDischargeAmountScreenOffSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged while screen doze: ");
+ pw.println(getDischargeAmountScreenDozeSinceCharge());
+ pw.println();
final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
helper.create(this);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index d5ef249..eb91860 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.Slog;
@@ -247,6 +248,7 @@
/**
* Raw native pointer to JavaBBinderHolder object. Owned by this Java object. Not null.
*/
+ @UnsupportedAppUsage
private final long mObject;
private IInterface mOwner;
@@ -990,6 +992,7 @@
}
// Entry point from android_util_Binder.cpp's onTransact
+ @UnsupportedAppUsage
private boolean execTransact(int code, long dataObj, long replyObj,
int flags) {
// At that point, the parcel request headers haven't been parsed so we do not know what
diff --git a/core/java/android/os/Broadcaster.java b/core/java/android/os/Broadcaster.java
index 70dcdd8..6ac7f1a 100644
--- a/core/java/android/os/Broadcaster.java
+++ b/core/java/android/os/Broadcaster.java
@@ -16,9 +16,12 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
+
/** @hide */
public class Broadcaster
{
+ @UnsupportedAppUsage
public Broadcaster()
{
}
@@ -29,6 +32,7 @@
* When this broadcaster pushes a message with senderWhat in the what field,
* target will be sent a copy of that message with targetWhat in the what field.
*/
+ @UnsupportedAppUsage
public void request(int senderWhat, Handler target, int targetWhat)
{
synchronized (this) {
@@ -96,6 +100,7 @@
/**
* Unregister for notifications for this senderWhat/target/targetWhat tuple.
*/
+ @UnsupportedAppUsage
public void cancelRequest(int senderWhat, Handler target, int targetWhat)
{
synchronized (this) {
@@ -168,6 +173,7 @@
* Send out msg. Anyone who has registered via the request() method will be
* sent the message.
*/
+ @UnsupportedAppUsage
public void broadcast(Message msg)
{
synchronized (this) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0de4ddc..94c8b91 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -22,6 +22,7 @@
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
import android.app.Application;
import android.content.Context;
@@ -321,6 +322,7 @@
/**
* @hide
*/
+ @UnsupportedAppUsage
public static final String[] ACTIVE_CODENAMES = "REL".equals(ALL_CODENAMES[0])
? new String[0] : ALL_CODENAMES;
@@ -1202,6 +1204,7 @@
* Returns true if we are running a debug build such as "user-debug" or "eng".
* @hide
*/
+ @UnsupportedAppUsage
public static final boolean IS_DEBUGGABLE =
SystemProperties.getInt("ro.debuggable", 0) == 1;
@@ -1249,6 +1252,7 @@
return TextUtils.isEmpty(propVal) ? null : propVal;
}
+ @UnsupportedAppUsage
private static String getString(String property) {
return SystemProperties.get(property, UNKNOWN);
}
@@ -1262,6 +1266,7 @@
}
}
+ @UnsupportedAppUsage
private static long getLong(String property) {
try {
return Long.parseLong(SystemProperties.get(property));
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 8e6a554..b82e517 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Size;
import android.util.SizeF;
@@ -173,6 +174,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static Bundle forPair(String key, String value) {
Bundle b = new Bundle(1);
b.putString(key, value);
@@ -229,6 +231,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static Bundle setDefusable(Bundle bundle, boolean defusable) {
if (bundle != null) {
bundle.setDefusable(defusable);
@@ -303,6 +306,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public int getSize() {
if (mParcelledData != null) {
return mParcelledData.dataSize();
@@ -385,6 +389,7 @@
* Filter values in Bundle to only basic types.
* @hide
*/
+ @UnsupportedAppUsage
public Bundle filterValues() {
unparcel();
Bundle bundle = this;
@@ -557,6 +562,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public void putParcelableList(String key, List<? extends Parcelable> value) {
unparcel();
mMap.put(key, value);
@@ -728,6 +734,7 @@
* @deprecated
* @hide This is the old name of the function.
*/
+ @UnsupportedAppUsage
@Deprecated
public void putIBinder(@Nullable String key, @Nullable IBinder value) {
unparcel();
@@ -928,12 +935,16 @@
}
/**
- * Returns the value associated with the given key, or null if
- * no mapping of the desired type exists for the given key or a null
+ * Returns the value associated with the given key, or {@code null} if
+ * no mapping of the desired type exists for the given key or a {@code null}
* value is explicitly associated with the key.
*
- * @param key a String, or null
- * @return a Parcelable value, or null
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @return a Parcelable value, or {@code null}
*/
@Nullable
public <T extends Parcelable> T getParcelable(@Nullable String key) {
@@ -951,12 +962,16 @@
}
/**
- * Returns the value associated with the given key, or null if
+ * Returns the value associated with the given key, or {@code null} if
* no mapping of the desired type exists for the given key or a null
* value is explicitly associated with the key.
*
- * @param key a String, or null
- * @return a Parcelable[] value, or null
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @return a Parcelable[] value, or {@code null}
*/
@Nullable
public Parcelable[] getParcelableArray(@Nullable String key) {
@@ -974,12 +989,16 @@
}
/**
- * Returns the value associated with the given key, or null if
- * no mapping of the desired type exists for the given key or a null
+ * Returns the value associated with the given key, or {@code null} if
+ * no mapping of the desired type exists for the given key or a {@code null}
* value is explicitly associated with the key.
*
- * @param key a String, or null
- * @return an ArrayList<T> value, or null
+ * <p><b>Note: </b> if the expected value is not a class provided by the Android platform,
+ * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
+ * Otherwise, this method might throw an exception or return {@code null}.
+ *
+ * @param key a String, or {@code null}
+ * @return an ArrayList<T> value, or {@code null}
*/
@Nullable
public <T extends Parcelable> ArrayList<T> getParcelableArrayList(@Nullable String key) {
@@ -1180,6 +1199,7 @@
* @deprecated
* @hide This is the old name of the function.
*/
+ @UnsupportedAppUsage
@Deprecated
@Nullable
public IBinder getIBinder(@Nullable String key) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a395ed4..1213eea 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.app.AppGlobals;
import android.content.Context;
import android.util.Log;
@@ -87,6 +88,7 @@
// set/cleared by waitForDebugger()
private static volatile boolean mWaiting = false;
+ @UnsupportedAppUsage
private Debug() {}
/*
@@ -115,8 +117,10 @@
public int dalvikPss;
/** The proportional set size that is swappable for dalvik heap. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int dalvikSwappablePss;
/** @hide The resident set size for dalvik heap. (Without other Dalvik overhead.) */
+ @UnsupportedAppUsage
public int dalvikRss;
/** The private dirty pages used by dalvik heap. */
public int dalvikPrivateDirty;
@@ -124,23 +128,29 @@
public int dalvikSharedDirty;
/** The private clean pages used by dalvik heap. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int dalvikPrivateClean;
/** The shared clean pages used by dalvik heap. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int dalvikSharedClean;
/** The dirty dalvik pages that have been swapped out. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int dalvikSwappedOut;
/** The dirty dalvik pages that have been swapped out, proportional. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int dalvikSwappedOutPss;
/** The proportional set size for the native heap. */
public int nativePss;
/** The proportional set size that is swappable for the native heap. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int nativeSwappablePss;
/** @hide The resident set size for the native heap. */
+ @UnsupportedAppUsage
public int nativeRss;
/** The private dirty pages used by the native heap. */
public int nativePrivateDirty;
@@ -148,23 +158,29 @@
public int nativeSharedDirty;
/** The private clean pages used by the native heap. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int nativePrivateClean;
/** The shared clean pages used by the native heap. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int nativeSharedClean;
/** The dirty native pages that have been swapped out. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int nativeSwappedOut;
/** The dirty native pages that have been swapped out, proportional. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int nativeSwappedOutPss;
/** The proportional set size for everything else. */
public int otherPss;
/** The proportional set size that is swappable for everything else. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int otherSwappablePss;
/** @hide The resident set size for everything else. */
+ @UnsupportedAppUsage
public int otherRss;
/** The private dirty pages used by everything else. */
public int otherPrivateDirty;
@@ -172,19 +188,24 @@
public int otherSharedDirty;
/** The private clean pages used by everything else. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int otherPrivateClean;
/** The shared clean pages used by everything else. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int otherSharedClean;
/** The dirty pages used by anyting else that have been swapped out. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int otherSwappedOut;
/** The dirty pages used by anyting else that have been swapped out, proportional. */
/** @hide We may want to expose this, eventually. */
+ @UnsupportedAppUsage
public int otherSwappedOutPss;
/** Whether the kernel reports proportional swap usage */
/** @hide */
+ @UnsupportedAppUsage
public boolean hasSwappedOutPss;
/** @hide */
@@ -231,6 +252,7 @@
// Needs to be declared here for the DVK_STAT ranges below.
/** @hide */
+ @UnsupportedAppUsage
public static final int NUM_OTHER_STATS = 17;
// Dalvik subsections.
@@ -291,6 +313,7 @@
public static final int OTHER_DVK_STAT_ART_END = OTHER_ART_BOOT - NUM_OTHER_STATS;
/** @hide */
+ @UnsupportedAppUsage
public static final int NUM_DVK_STATS = 14;
/** @hide */
@@ -315,6 +338,7 @@
/** @hide */
public static final int OFFSET_SWAPPED_OUT_PSS = 8;
+ @UnsupportedAppUsage
private int[] otherStats = new int[(NUM_OTHER_STATS+NUM_DVK_STATS)*NUM_CATEGORIES];
public MemoryInfo() {
@@ -369,6 +393,7 @@
/**
* @hide Return total PSS memory usage in kB.
*/
+ @UnsupportedAppUsage
public int getTotalUss() {
return dalvikPrivateClean + dalvikPrivateDirty
+ nativePrivateClean + nativePrivateDirty
@@ -435,6 +460,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public int getOtherPss(int which) {
return otherStats[which * NUM_CATEGORIES + OFFSET_PSS];
}
@@ -450,11 +476,13 @@
}
/** @hide */
+ @UnsupportedAppUsage
public int getOtherPrivateDirty(int which) {
return otherStats[which * NUM_CATEGORIES + OFFSET_PRIVATE_DIRTY];
}
/** @hide */
+ @UnsupportedAppUsage
public int getOtherSharedDirty(int which) {
return otherStats[which * NUM_CATEGORIES + OFFSET_SHARED_DIRTY];
}
@@ -465,6 +493,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public int getOtherPrivate(int which) {
return getOtherPrivateClean(which) + getOtherPrivateDirty(which);
}
@@ -485,6 +514,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static String getOtherLabel(int which) {
switch (which) {
case OTHER_DALVIK_OTHER: return "Dalvik Other";
@@ -662,6 +692,7 @@
* such thing as private clean for the Java Heap.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummaryJavaHeap() {
return dalvikPrivateDirty + getOtherPrivate(OTHER_ART);
}
@@ -674,6 +705,7 @@
* such thing as private clean for the Native Heap.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummaryNativeHeap() {
return nativePrivateDirty;
}
@@ -683,6 +715,7 @@
* the application.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummaryCode() {
return getOtherPrivate(OTHER_SO)
+ getOtherPrivate(OTHER_JAR)
@@ -701,6 +734,7 @@
* such thing as private clean for the stack.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummaryStack() {
return getOtherPrivateDirty(OTHER_STACK);
}
@@ -716,6 +750,7 @@
* memory into the System category.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummaryGraphics() {
return getOtherPrivate(OTHER_GL_DEV)
+ getOtherPrivate(OTHER_GRAPHICS)
@@ -727,6 +762,7 @@
* accounted for.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummaryPrivateOther() {
return getTotalPrivateClean()
+ getTotalPrivateDirty()
@@ -743,6 +779,7 @@
* * Includes all shared memory.
* @hide
*/
+ @UnsupportedAppUsage
public int getSummarySystem() {
return getTotalPss()
- getTotalPrivateClean()
@@ -1782,6 +1819,7 @@
* as the caller.
* @hide
*/
+ @UnsupportedAppUsage
public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
/**
@@ -1837,6 +1875,7 @@
* as defined by MEMINFO_* offsets.
* @hide
*/
+ @UnsupportedAppUsage
public static native void getMemInfo(long[] outSizes);
/**
@@ -1925,6 +1964,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static native void dumpNativeHeap(FileDescriptor fd);
/**
@@ -1939,6 +1979,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static long countInstancesOfClass(Class cls) {
return VMDebug.countInstancesOfClass(cls, true);
}
@@ -1998,6 +2039,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static final void dumpReferenceTables() {
VMDebug.dumpReferenceTables();
}
@@ -2364,6 +2406,7 @@
* @return a string describing the call stack.
* {@hide}
*/
+ @UnsupportedAppUsage
public static String getCallers(final int depth) {
final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
StringBuffer sb = new StringBuffer();
@@ -2410,6 +2453,7 @@
* @return a String describing the immediate caller of the calling method.
* {@hide}
*/
+ @UnsupportedAppUsage
public static String getCaller() {
return getCaller(Thread.currentThread().getStackTrace(), 0);
}
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 1be7b6b..320f471 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -24,6 +24,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.util.Log;
@@ -50,6 +51,7 @@
private static final String TAG = "DropBoxManager";
private final Context mContext;
+ @UnsupportedAppUsage
private final IDropBoxManagerService mService;
/** Flag value: Entry's content was deleted to save space. */
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index fea69c0..cceb6ed 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.os.storage.StorageManager;
@@ -74,6 +75,7 @@
private static final File DIR_PRODUCT_SERVICES_ROOT = getDirectory(ENV_PRODUCT_SERVICES_ROOT,
"/product_services");
+ @UnsupportedAppUsage
private static UserEnvironment sCurrentUser;
private static boolean sUserRequired;
@@ -82,6 +84,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static void initForCurrentUser() {
final int userId = UserHandle.myUserId();
sCurrentUser = new UserEnvironment(userId);
@@ -91,10 +94,12 @@
public static class UserEnvironment {
private final int mUserId;
+ @UnsupportedAppUsage
public UserEnvironment(int userId) {
mUserId = userId;
}
+ @UnsupportedAppUsage
public File[] getExternalDirs() {
final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
StorageManager.FLAG_FOR_WRITE);
@@ -105,11 +110,13 @@
return files;
}
+ @UnsupportedAppUsage
@Deprecated
public File getExternalStorageDirectory() {
return getExternalDirs()[0];
}
+ @UnsupportedAppUsage
@Deprecated
public File getExternalStoragePublicDirectory(String type) {
return buildExternalStoragePublicDirs(type)[0];
@@ -278,6 +285,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static File getDataSystemDirectory() {
return new File(getDataDirectory(), "system");
}
@@ -553,11 +561,13 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static File getLegacyExternalStorageDirectory() {
return new File(System.getenv(ENV_EXTERNAL_STORAGE));
}
/** {@hide} */
+ @UnsupportedAppUsage
public static File getLegacyExternalStorageObbDirectory() {
return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
}
@@ -839,6 +849,7 @@
* Returns the path for android-specific data on the SD card.
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildExternalStorageAndroidDataDirs() {
throwIfUserRequired();
return sCurrentUser.buildExternalStorageAndroidDataDirs();
@@ -848,6 +859,7 @@
* Generates the raw path to an application's data
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildExternalStorageAppDataDirs(String packageName) {
throwIfUserRequired();
return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
@@ -857,6 +869,7 @@
* Generates the raw path to an application's media
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildExternalStorageAppMediaDirs(String packageName) {
throwIfUserRequired();
return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
@@ -866,6 +879,7 @@
* Generates the raw path to an application's OBB files
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildExternalStorageAppObbDirs(String packageName) {
throwIfUserRequired();
return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
@@ -875,6 +889,7 @@
* Generates the path to an application's files.
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildExternalStorageAppFilesDirs(String packageName) {
throwIfUserRequired();
return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
@@ -884,6 +899,7 @@
* Generates the path to an application's cache.
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildExternalStorageAppCacheDirs(String packageName) {
throwIfUserRequired();
return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
@@ -1118,6 +1134,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static File[] buildPaths(File[] base, String... segments) {
File[] result = new File[base.length];
for (int i = 0; i < base.length; i++) {
@@ -1157,6 +1174,7 @@
* @deprecated disabled now that FUSE has been replaced by sdcardfs
* @hide
*/
+ @UnsupportedAppUsage
@Deprecated
public static File maybeTranslateEmulatedPathToInternal(File path) {
return StorageManager.maybeTranslateEmulatedPathToInternal(path);
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 330bde5..4d9ebc2 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.util.Log;
import java.io.File;
@@ -141,6 +142,7 @@
stopWatching(m_fd, descriptors);
}
+ @UnsupportedAppUsage
public void onEvent(int wfd, @NotifyEventType int mask, String path) {
// look up our observer, fixing up the map if necessary...
FileObserver observer = null;
@@ -172,6 +174,7 @@
private native void stopWatching(int fd, int[] wfds);
}
+ @UnsupportedAppUsage
private static ObserverThread s_observerThread;
static {
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 316572c..f789b72 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -40,6 +40,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.provider.DocumentsContract.Document;
import android.system.ErrnoException;
@@ -103,6 +104,7 @@
/** {@hide} */ public static final int S_IWOTH = 00002;
/** {@hide} */ public static final int S_IXOTH = 00001;
+ @UnsupportedAppUsage
private FileUtils() {
}
@@ -135,6 +137,7 @@
* @return 0 on success, otherwise errno.
* @hide
*/
+ @UnsupportedAppUsage
public static int setPermissions(File path, int mode, int uid, int gid) {
return setPermissions(path.getAbsolutePath(), mode, uid, gid);
}
@@ -148,6 +151,7 @@
* @return 0 on success, otherwise errno.
* @hide
*/
+ @UnsupportedAppUsage
public static int setPermissions(String path, int mode, int uid, int gid) {
try {
Os.chmod(path, mode);
@@ -177,6 +181,7 @@
* @return 0 on success, otherwise errno.
* @hide
*/
+ @UnsupportedAppUsage
public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
try {
Os.fchmod(fd, mode);
@@ -233,6 +238,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static boolean sync(FileOutputStream stream) {
try {
if (stream != null) {
@@ -248,6 +254,7 @@
* @deprecated use {@link #copy(File, File)} instead.
* @hide
*/
+ @UnsupportedAppUsage
@Deprecated
public static boolean copyFile(File srcFile, File destFile) {
try {
@@ -273,6 +280,7 @@
* @deprecated use {@link #copy(InputStream, OutputStream)} instead.
* @hide
*/
+ @UnsupportedAppUsage
@Deprecated
public static boolean copyToFile(InputStream inputStream, File destFile) {
try {
@@ -584,6 +592,7 @@
* @param file The file to check
* @hide
*/
+ @UnsupportedAppUsage
public static boolean isFilenameSafe(File file) {
// Note, we check whether it matches what's known to be safe,
// rather than what's known to be unsafe. Non-ASCII, control
@@ -600,6 +609,7 @@
* @throws IOException if something goes wrong reading the file
* @hide
*/
+ @UnsupportedAppUsage
public static String readTextFile(File file, int max, String ellipsis) throws IOException {
InputStream input = new FileInputStream(file);
// wrapping a BufferedInputStream around it because when reading /proc with unbuffered
@@ -654,6 +664,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static void stringToFile(File file, String string) throws IOException {
stringToFile(file.getAbsolutePath(), string);
}
@@ -687,6 +698,7 @@
* @throws IOException
* @hide
*/
+ @UnsupportedAppUsage
public static void stringToFile(String filename, String string) throws IOException {
bytesToFile(filename, string.getBytes(StandardCharsets.UTF_8));
}
@@ -701,6 +713,7 @@
* to its potential for collision.
* @hide
*/
+ @UnsupportedAppUsage
@Deprecated
public static long checksumCrc32(File file) throws FileNotFoundException, IOException {
CRC32 checkSummer = new CRC32();
@@ -783,6 +796,7 @@
* @return if any files were deleted.
* @hide
*/
+ @UnsupportedAppUsage
public static boolean deleteOlderFiles(File dir, int minCount, long minAgeMs) {
if (minCount < 0 || minAgeMs < 0) {
throw new IllegalArgumentException("Constraints must be positive or 0");
@@ -891,6 +905,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 39e9138..707a404 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -82,12 +82,18 @@
public void setup(Context context, Bundle coreSettings) {
final PackageManager pm = context.getPackageManager();
final String packageName = context.getPackageName();
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
setupGpuLayers(context, coreSettings, pm, packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
setupAngle(context, coreSettings, pm, packageName);
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+ Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
if (!chooseDriver(context, coreSettings, pm, packageName)) {
setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
}
+ Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
}
/**
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index a039742..9af9eda 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.Printer;
@@ -168,6 +169,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public Handler(boolean async) {
this(null, async);
}
@@ -229,6 +231,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
@@ -274,6 +277,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
@NonNull
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
@@ -843,6 +847,7 @@
+ "}";
}
+ @UnsupportedAppUsage
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
@@ -866,6 +871,7 @@
return m;
}
+ @UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
@@ -877,10 +883,13 @@
message.callback.run();
}
+ @UnsupportedAppUsage
final Looper mLooper;
final MessageQueue mQueue;
+ @UnsupportedAppUsage
final Callback mCallback;
final boolean mAsynchronous;
+ @UnsupportedAppUsage
IMessenger mMessenger;
private static final class BlockingRunnable implements Runnable {
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 9e3e83e..09afdc7 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -18,6 +18,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import libcore.util.NativeAllocationRegistry;
@@ -151,6 +152,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void reportSyspropChanged() {
native_report_sysprop_change();
}
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index dc640c9..cfb582e 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import libcore.util.NativeAllocationRegistry;
@@ -49,6 +50,7 @@
private static final NativeAllocationRegistry sNativeRegistry;
+ @UnsupportedAppUsage
private HwParcel(boolean allocate) {
native_setup(allocate);
diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java
index a07e42c..72ec958 100644
--- a/core/java/android/os/HwRemoteBinder.java
+++ b/core/java/android/os/HwRemoteBinder.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import libcore.util.NativeAllocationRegistry;
/** @hide */
@@ -24,6 +25,7 @@
private static final NativeAllocationRegistry sNativeRegistry;
+ @UnsupportedAppUsage
public HwRemoteBinder() {
native_setup_empty();
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index e74b0bb..83f88ad 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import java.io.FileDescriptor;
@@ -149,6 +150,7 @@
int LIKE_TRANSACTION = ('_'<<24)|('L'<<16)|('I'<<8)|'K';
/** @hide */
+ @UnsupportedAppUsage
int SYSPROPS_TRANSACTION = ('_'<<24)|('S'<<16)|('P'<<8)|'R';
/**
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index fe17c6b..aa255bf 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -39,6 +39,7 @@
int[] getAppIdTempWhitelist();
boolean isPowerSaveWhitelistExceptIdleApp(String name);
boolean isPowerSaveWhitelistApp(String name);
+ @UnsupportedAppUsage
void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 8ced722..6536fc9 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -38,11 +38,13 @@
/**
* Register an observer to receive events.
*/
+ @UnsupportedAppUsage
void registerObserver(INetworkManagementEventObserver obs);
/**
* Unregister an observer from receiving events.
*/
+ @UnsupportedAppUsage
void unregisterObserver(INetworkManagementEventObserver obs);
/**
@@ -54,16 +56,19 @@
* Retrieves the specified interface config
*
*/
+ @UnsupportedAppUsage
InterfaceConfiguration getInterfaceConfig(String iface);
/**
* Sets the configuration of the specified interface
*/
+ @UnsupportedAppUsage
void setInterfaceConfig(String iface, in InterfaceConfiguration cfg);
/**
* Clear all IP addresses on the specified interface
*/
+ @UnsupportedAppUsage
void clearInterfaceAddresses(String iface);
/**
@@ -79,22 +84,26 @@
/**
* Set interface IPv6 privacy extensions
*/
+ @UnsupportedAppUsage
void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable);
/**
* Disable IPv6 on an interface
*/
+ @UnsupportedAppUsage
void disableIpv6(String iface);
/**
* Enable IPv6 on an interface
*/
+ @UnsupportedAppUsage
void enableIpv6(String iface);
/**
* Set IPv6 autoconf address generation mode.
* This is a no-op if an unsupported mode is requested.
*/
+ @UnsupportedAppUsage
void setIPv6AddrGenMode(String iface, int mode);
/**
@@ -124,37 +133,44 @@
/**
* Returns true if IP forwarding is enabled
*/
+ @UnsupportedAppUsage
boolean getIpForwardingEnabled();
/**
* Enables/Disables IP Forwarding
*/
+ @UnsupportedAppUsage
void setIpForwardingEnabled(boolean enabled);
/**
* Start tethering services with the specified dhcp server range
* arg is a set of start end pairs defining the ranges.
*/
+ @UnsupportedAppUsage
void startTethering(in String[] dhcpRanges);
/**
* Stop currently running tethering services
*/
+ @UnsupportedAppUsage
void stopTethering();
/**
* Returns true if tethering services are started
*/
+ @UnsupportedAppUsage
boolean isTetheringStarted();
/**
* Tethers the specified interface
*/
+ @UnsupportedAppUsage
void tetherInterface(String iface);
/**
* Untethers the specified interface
*/
+ @UnsupportedAppUsage
void untetherInterface(String iface);
/**
@@ -189,11 +205,13 @@
* The address and netmask of the external interface is used for
* the NAT'ed network.
*/
+ @UnsupportedAppUsage
void enableNat(String internalInterface, String externalInterface);
/**
* Disables Network Address Translation between two interfaces.
*/
+ @UnsupportedAppUsage
void disableNat(String internalInterface, String externalInterface);
/**
@@ -224,27 +242,6 @@
void tetherLimitReached(ITetheringStatsProvider provider);
/**
- ** PPPD
- **/
-
- /**
- * Returns the list of currently known TTY devices on the system
- */
- String[] listTtys();
-
- /**
- * Attaches a PPP server daemon to the specified TTY with the specified
- * local/remote addresses.
- */
- void attachPppd(String tty, String localAddr, String remoteAddr, String dns1Addr,
- String dns2Addr);
-
- /**
- * Detaches a PPP server daemon from the specified TTY.
- */
- void detachPppd(String tty);
-
- /**
** DATA USAGE RELATED
**/
@@ -311,6 +308,7 @@
/**
* Return status of bandwidth control module.
*/
+ @UnsupportedAppUsage
boolean isBandwidthControlEnabled();
/**
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index a0d88ee..4233340 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -41,10 +41,13 @@
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws, String historyTag);
boolean isWakeLockLevelSupported(int level);
+ @UnsupportedAppUsage
void userActivity(long time, int event, int flags);
void wakeUp(long time, int reason, String details, String opPackageName);
+ @UnsupportedAppUsage
void goToSleep(long time, int reason, int flags);
void nap(long time);
+ @UnsupportedAppUsage
boolean isInteractive();
boolean isPowerSaveMode();
PowerSaveState getPowerSaveState(int serviceType);
@@ -56,6 +59,7 @@
boolean isDeviceIdleMode();
boolean isLightDeviceIdleMode();
+ @UnsupportedAppUsage
void reboot(boolean confirm, String reason, boolean wait);
void rebootSafeMode(boolean confirm, boolean wait);
void shutdown(boolean confirm, String reason, boolean wait);
diff --git a/core/java/android/os/IRemoteCallback.aidl b/core/java/android/os/IRemoteCallback.aidl
index f0c6c73..71f3b06 100644
--- a/core/java/android/os/IRemoteCallback.aidl
+++ b/core/java/android/os/IRemoteCallback.aidl
@@ -21,5 +21,6 @@
/** @hide */
oneway interface IRemoteCallback {
+ @UnsupportedAppUsage
void sendResult(in Bundle data);
}
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
index 89bf7b9..bc0690d 100644
--- a/core/java/android/os/IServiceManager.java
+++ b/core/java/android/os/IServiceManager.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
+
/**
* Basic interface for finding and publishing system services.
*
@@ -33,12 +35,14 @@
* service manager. Blocks for a few seconds waiting for it to be
* published if it does not already exist.
*/
+ @UnsupportedAppUsage
IBinder getService(String name) throws RemoteException;
/**
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
*/
+ @UnsupportedAppUsage
IBinder checkService(String name) throws RemoteException;
/**
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3017f25..63641e5 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -59,6 +59,7 @@
boolean canAddMoreManagedProfiles(int userHandle, boolean allowedToRemoveOne);
UserInfo getProfileParent(int userHandle);
boolean isSameProfileGroup(int userHandle, int otherUserHandle);
+ @UnsupportedAppUsage
UserInfo getUserInfo(int userHandle);
String getUserAccount(int userHandle);
void setUserAccount(int userHandle, String accountName);
@@ -100,6 +101,7 @@
boolean isUserNameSet(int userHandle);
boolean hasRestrictedProfiles();
boolean requestQuietModeEnabled(String callingPackage, boolean enableQuietMode, int userHandle, in IntentSender target);
+ String getUserName();
long getUserStartRealtime();
long getUserUnlockRealtime();
}
diff --git a/core/java/android/os/LocaleList.java b/core/java/android/os/LocaleList.java
index a9da080..351df1b 100644
--- a/core/java/android/os/LocaleList.java
+++ b/core/java/android/os/LocaleList.java
@@ -21,6 +21,7 @@
import android.annotation.Nullable;
import android.annotation.Size;
import android.annotation.SystemApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.LocaleProto;
import android.icu.util.ULocale;
import android.util.proto.ProtoOutputStream;
@@ -568,6 +569,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public static void setDefault(@NonNull @Size(min=1) LocaleList locales, int localeIndex) {
if (locales == null) {
throw new NullPointerException("locales is null");
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index a8d1215..3222fc4 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.Printer;
import android.util.Slog;
@@ -67,13 +68,17 @@
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
+ @UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
+ @UnsupportedAppUsage
private static Looper sMainLooper; // guarded by Looper.class
private static Observer sObserver;
+ @UnsupportedAppUsage
final MessageQueue mQueue;
final Thread mThread;
+ @UnsupportedAppUsage
private Printer mLogging;
private long mTraceTag;
@@ -315,6 +320,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public void setTraceTag(long traceTag) {
mTraceTag = traceTag;
}
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index ff3258f..5a1e3d4 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.system.ErrnoException;
import java.io.FileDescriptor;
@@ -40,7 +41,9 @@
private static String TAG = "MemoryFile";
// Returns 'true' if purged, 'false' otherwise
+ @UnsupportedAppUsage
private static native boolean native_pin(FileDescriptor fd, boolean pin) throws IOException;
+ @UnsupportedAppUsage
private static native int native_get_size(FileDescriptor fd) throws IOException;
private SharedMemory mSharedMemory;
@@ -79,6 +82,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
void deactivate() {
if (mMapping != null) {
SharedMemory.unmap(mMapping);
@@ -222,6 +226,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public FileDescriptor getFileDescriptor() throws IOException {
return mSharedMemory.getFileDescriptor();
}
@@ -234,6 +239,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static int getSize(FileDescriptor fd) throws IOException {
return native_get_size(fd);
}
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 317579e..6055bef 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -111,6 +112,7 @@
/** Flags to clear in the copyFrom method */
/*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
+ @UnsupportedAppUsage
/*package*/ int flags;
/**
@@ -118,16 +120,20 @@
* {@link SystemClock#uptimeMillis}.
* @hide Only for use within the tests.
*/
+ @UnsupportedAppUsage
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public long when;
/*package*/ Bundle data;
+ @UnsupportedAppUsage
/*package*/ Handler target;
+ @UnsupportedAppUsage
/*package*/ Runnable callback;
// sometimes we store linked lists of these things
+ @UnsupportedAppUsage
/*package*/ Message next;
@@ -314,6 +320,7 @@
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
*/
+ @UnsupportedAppUsage
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
@@ -397,6 +404,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public Message setCallback(Runnable r) {
callback = r;
return this;
@@ -510,6 +518,7 @@
return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}
+ @UnsupportedAppUsage
/*package*/ void markInUse() {
flags |= FLAG_IN_USE;
}
@@ -524,6 +533,7 @@
return toString(SystemClock.uptimeMillis());
}
+ @UnsupportedAppUsage
String toString(long now) {
StringBuilder b = new StringBuilder();
b.append("{ when=");
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 7c2ecc5..c5f1698 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.os.MessageQueueProto;
import android.util.Log;
import android.util.Printer;
@@ -43,12 +44,16 @@
private static final boolean DEBUG = false;
// True if the message queue can be quit.
+ @UnsupportedAppUsage
private final boolean mQuitAllowed;
+ @UnsupportedAppUsage
@SuppressWarnings("unused")
private long mPtr; // used by native code
+ @UnsupportedAppUsage
Message mMessages;
+ @UnsupportedAppUsage
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
@@ -59,10 +64,12 @@
// The next barrier token.
// Barriers are indicated by messages with a null target whose arg1 field carries the token.
+ @UnsupportedAppUsage
private int mNextBarrierToken;
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
+ @UnsupportedAppUsage
private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
@@ -260,6 +267,7 @@
}
// Called from native code.
+ @UnsupportedAppUsage
private int dispatchEvents(int fd, int events) {
// Get the file descriptor record and any state that might change.
final FileDescriptorRecord record;
@@ -308,6 +316,7 @@
return newWatchedEvents;
}
+ @UnsupportedAppUsage
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
@@ -607,6 +616,7 @@
}
}
+ @UnsupportedAppUsage
boolean hasMessages(Handler h, Runnable r, Object object) {
if (h == null) {
return false;
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 79e9ba5..de963c9 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -197,6 +198,7 @@
private static final boolean DEBUG_ARRAY_MAP = false;
private static final String TAG = "Parcel";
+ @UnsupportedAppUsage
@SuppressWarnings({"UnusedDeclaration"})
private long mNativePtr; // used by native code
@@ -453,9 +455,11 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static native long getGlobalAllocSize();
/** @hide */
+ @UnsupportedAppUsage
public static native long getGlobalAllocCount();
/**
@@ -679,6 +683,7 @@
* {@hide}
* {@SystemApi}
*/
+ @UnsupportedAppUsage
public final void writeBlob(@Nullable byte[] b) {
writeBlob(b, 0, (b != null) ? b.length : 0);
}
@@ -768,6 +773,7 @@
* growing dataCapacity() if needed.
* @hide
*/
+ @UnsupportedAppUsage
public final void writeCharSequence(@Nullable CharSequence val) {
TextUtils.writeToParcel(val, this, 0);
}
@@ -929,6 +935,7 @@
/**
* @hide For testing only.
*/
+ @UnsupportedAppUsage
public void writeArrayMap(@Nullable ArrayMap<String, Object> val) {
writeArrayMapInternal(val);
}
@@ -967,6 +974,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public void writeArraySet(@Nullable ArraySet<? extends Object> val) {
final int size = (val != null) ? val.size() : -1;
writeInt(size);
@@ -1793,6 +1801,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public final void writeParcelableCreator(@NonNull Parcelable p) {
String name = p.getClass().getName();
writeString(name);
@@ -1991,6 +2000,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public final int readExceptionCode() {
int code = readInt();
if (code == EX_HAS_REPLY_HEADER) {
@@ -2137,6 +2147,7 @@
* Read a CharSequence value from the parcel at the current dataPosition().
* @hide
*/
+ @UnsupportedAppUsage
@Nullable
public final CharSequence readCharSequence() {
return TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(this);
@@ -2158,6 +2169,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public final FileDescriptor readRawFileDescriptor() {
return nativeReadFileDescriptor(mNativePtr);
}
@@ -2349,6 +2361,7 @@
* {@hide}
* {@SystemApi}
*/
+ @UnsupportedAppUsage
@Nullable
public final byte[] readBlob() {
return nativeReadBlob(mNativePtr);
@@ -2358,6 +2371,7 @@
* Read and return a String[] object from the parcel.
* {@hide}
*/
+ @UnsupportedAppUsage
@Nullable
public final String[] readStringArray() {
String[] array = null;
@@ -2958,6 +2972,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
@SuppressWarnings("unchecked")
@Nullable
public final <T extends Parcelable> T readCreator(@NonNull Parcelable.Creator<?> creator,
@@ -2971,6 +2986,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
@Nullable
public final Parcelable.Creator<?> readParcelableCreator(@Nullable ClassLoader loader) {
String name = readString();
@@ -3253,6 +3269,7 @@
/**
* @hide For testing only.
*/
+ @UnsupportedAppUsage
public void readArrayMap(@NonNull ArrayMap outVal, @Nullable ClassLoader loader) {
final int N = readInt();
if (N < 0) {
@@ -3268,6 +3285,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public @Nullable ArraySet<? extends Object> readArraySet(@Nullable ClassLoader loader) {
final int size = readInt();
if (size < 0) {
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 7a8727c..8355e08 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -32,6 +32,7 @@
import static android.system.OsConstants.S_IWOTH;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
import android.os.MessageQueue.OnFileDescriptorEventListener;
@@ -178,6 +179,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public ParcelFileDescriptor(FileDescriptor fd) {
this(fd, null);
}
@@ -372,7 +374,11 @@
/**
* Take ownership of a raw native fd in to a new ParcelFileDescriptor.
* The returned ParcelFileDescriptor now owns the given fd, and will be
- * responsible for closing it. You must not close the fd yourself.
+ * responsible for closing it.
+ * <p>
+ * <strong>WARNING:</strong> You must not close the fd yourself after
+ * this call, and ownership of the file descriptor must have been
+ * released prior to the call to this function.
*
* @param fd The native fd that the ParcelFileDescriptor should adopt.
*
@@ -391,6 +397,16 @@
* ParcelFileDescriptor holds a dup of the original FileDescriptor in
* the Socket, so you must still close the Socket as well as the new
* ParcelFileDescriptor.
+ * <p>
+ * <strong>WARNING:</strong> Prior to API level 29, this function would not
+ * actually dup the Socket's FileDescriptor, and would take a
+ * reference to the its internal FileDescriptor instead. If the Socket
+ * gets garbage collected before the ParcelFileDescriptor, this may
+ * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
+ * this, the following pattern can be used:
+ * <pre>{@code
+ * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket).dup();
+ * }</pre>
*
* @param socket The Socket whose FileDescriptor is used to create
* a new ParcelFileDescriptor.
@@ -414,6 +430,16 @@
* new ParcelFileDescriptor holds a dup of the original FileDescriptor in
* the DatagramSocket, so you must still close the DatagramSocket as well
* as the new ParcelFileDescriptor.
+ * <p>
+ * <strong>WARNING:</strong> Prior to API level 29, this function would not
+ * actually dup the DatagramSocket's FileDescriptor, and would take a
+ * reference to the its internal FileDescriptor instead. If the DatagramSocket
+ * gets garbage collected before the ParcelFileDescriptor, this may
+ * lead to the ParcelFileDescriptor being unexpectedly closed. To avoid
+ * this, the following pattern can be used:
+ * <pre>{@code
+ * ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket).dup();
+ * }</pre>
*
* @param datagramSocket The DatagramSocket whose FileDescriptor is used
* to create a new ParcelFileDescriptor.
@@ -550,6 +576,7 @@
* @return A ParcelFileDescriptor.
* @throws IOException if there is an error while creating the shared memory area.
*/
+ @UnsupportedAppUsage
@Deprecated
public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
if (data == null) return null;
@@ -635,6 +662,7 @@
* and I really don't think we want it to be public.
* @hide
*/
+ @UnsupportedAppUsage
public long seekTo(long pos) throws IOException {
if (mWrapped != null) {
return mWrapped.seekTo(pos);
@@ -651,6 +679,9 @@
* Return the native fd int for this ParcelFileDescriptor. The
* ParcelFileDescriptor still owns the fd, and it still must be closed
* through this API.
+ * <p>
+ * <strong>WARNING:</strong> Do not call close on the return value of this
+ * function or pass it to a function that assumes ownership of the fd.
*/
public int getFd() {
if (mWrapped != null) {
diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java
index 5bbe6488..61f3968 100644
--- a/core/java/android/os/ParcelableParcel.java
+++ b/core/java/android/os/ParcelableParcel.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.MathUtils;
/**
@@ -26,6 +27,7 @@
final Parcel mParcel;
final ClassLoader mClassLoader;
+ @UnsupportedAppUsage
public ParcelableParcel(ClassLoader loader) {
mParcel = Parcel.obtain();
mClassLoader = loader;
@@ -44,11 +46,13 @@
mParcel.appendFrom(src, pos, size);
}
+ @UnsupportedAppUsage
public Parcel getParcel() {
mParcel.setDataPosition(0);
return mParcel;
}
+ @UnsupportedAppUsage
public ClassLoader getClassLoader() {
return mClassLoader;
}
@@ -64,6 +68,7 @@
dest.appendFrom(mParcel, 0, mParcel.dataSize());
}
+ @UnsupportedAppUsage
public static final Parcelable.ClassLoaderCreator<ParcelableParcel> CREATOR
= new Parcelable.ClassLoaderCreator<ParcelableParcel>() {
public ParcelableParcel createFromParcel(Parcel in) {
diff --git a/core/java/android/os/PerformanceCollector.java b/core/java/android/os/PerformanceCollector.java
index be1cf6d..33c86b8 100644
--- a/core/java/android/os/PerformanceCollector.java
+++ b/core/java/android/os/PerformanceCollector.java
@@ -17,6 +17,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
/**
@@ -285,6 +286,7 @@
private long mCpuTime;
private long mExecTime;
+ @UnsupportedAppUsage
public PerformanceCollector() {
}
@@ -302,6 +304,7 @@
* @param label description of code block between beginSnapshot and
* endSnapshot, used to label output
*/
+ @UnsupportedAppUsage
public void beginSnapshot(String label) {
if (mPerfWriter != null)
mPerfWriter.writeBeginSnapshot(label);
@@ -346,6 +349,7 @@
* <li>{@link #METRIC_KEY_OTHER_SHARED_DIRTY other_shared_dirty}
* </ul>
*/
+ @UnsupportedAppUsage
public Bundle endSnapshot() {
endPerformanceSnapshot();
if (mPerfWriter != null)
@@ -359,6 +363,7 @@
* @param label description of code block between startTiming and
* stopTiming, used to label output
*/
+ @UnsupportedAppUsage
public void startTiming(String label) {
if (mPerfWriter != null)
mPerfWriter.writeStartTiming(label);
@@ -408,6 +413,7 @@
* between calls to startTiming and stopTiming. List of iterations
* is keyed by {@link #METRIC_KEY_ITERATIONS iterations}.
*/
+ @UnsupportedAppUsage
public Bundle stopTiming(String label) {
addIteration(label);
if (mPerfWriter != null)
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index fdc5157..36bae2d 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.service.dreams.Sandman;
import android.util.ArrayMap;
@@ -290,6 +291,7 @@
* Brightness value for fully on.
* @hide
*/
+ @UnsupportedAppUsage
public static final int BRIGHTNESS_ON = 255;
/**
@@ -384,6 +386,7 @@
* Go to sleep reason code: Going to sleep due to a screen timeout.
* @hide
*/
+ @UnsupportedAppUsage
public static final int GO_TO_SLEEP_REASON_TIMEOUT = 2;
/**
@@ -805,6 +808,7 @@
}
final Context mContext;
+ @UnsupportedAppUsage
final IPowerManager mService;
final Handler mHandler;
@@ -829,6 +833,7 @@
* this is the minimum value that can be set by the user.
* @hide
*/
+ @UnsupportedAppUsage
public int getMinimumScreenBrightnessSetting() {
return mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
@@ -840,6 +845,7 @@
* this is the maximum value that can be set by the user.
* @hide
*/
+ @UnsupportedAppUsage
public int getMaximumScreenBrightnessSetting() {
return mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingMaximum);
@@ -849,6 +855,7 @@
* Gets the default screen brightness setting.
* @hide
*/
+ @UnsupportedAppUsage
public int getDefaultScreenBrightnessSetting() {
return mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingDefault);
@@ -963,6 +970,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static void validateWakeLockParameters(int levelAndFlags, String tag) {
switch (levelAndFlags & WAKE_LOCK_LEVEL_MASK) {
case PARTIAL_WAKE_LOCK:
@@ -1095,6 +1103,7 @@
*
* @hide Requires signature permission.
*/
+ @UnsupportedAppUsage
public void goToSleep(long time, int reason, int flags) {
try {
mService.goToSleep(time, reason, flags);
@@ -1151,6 +1160,7 @@
* @deprecated Use {@link #wakeUp(long, int, String)} instead.
* @hide
*/
+ @UnsupportedAppUsage
@Deprecated
public void wakeUp(long time, String details) {
wakeUp(time, WAKE_REASON_UNKNOWN, details);
@@ -1635,6 +1645,7 @@
* restrictions have been lifted.
* @hide
*/
+ @UnsupportedAppUsage
public boolean isLightDeviceIdleMode() {
try {
return mService.isLightDeviceIdleMode();
@@ -1970,6 +1981,7 @@
* This broadcast is only sent to registered receivers.
* @hide
*/
+ @UnsupportedAppUsage
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED
= "android.os.action.LIGHT_DEVICE_IDLE_MODE_CHANGED";
@@ -1996,11 +2008,13 @@
*
* @hide
*/
+ @UnsupportedAppUsage
@SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_POWER_SAVE_MODE_CHANGING
= "android.os.action.POWER_SAVE_MODE_CHANGING";
/** @hide */
+ @UnsupportedAppUsage
public static final String EXTRA_POWER_SAVE_MODE = "mode";
/**
@@ -2051,7 +2065,9 @@
* </p>
*/
public final class WakeLock {
+ @UnsupportedAppUsage
private int mFlags;
+ @UnsupportedAppUsage
private String mTag;
private final String mPackageName;
private final IBinder mToken;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 03fc2a9..a7ac7a1 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.system.Os;
import android.system.OsConstants;
import android.webkit.WebViewZygote;
@@ -60,30 +61,35 @@
* Defines the UID/GID for the log group.
* @hide
*/
+ @UnsupportedAppUsage
public static final int LOG_UID = 1007;
/**
* Defines the UID/GID for the WIFI supplicant process.
* @hide
*/
+ @UnsupportedAppUsage
public static final int WIFI_UID = 1010;
/**
* Defines the UID/GID for the mediaserver process.
* @hide
*/
+ @UnsupportedAppUsage
public static final int MEDIA_UID = 1013;
/**
* Defines the UID/GID for the DRM process.
* @hide
*/
+ @UnsupportedAppUsage
public static final int DRM_UID = 1019;
/**
* Defines the UID/GID for the group that controls VPN services.
* @hide
*/
+ @UnsupportedAppUsage
public static final int VPN_UID = 1016;
/**
@@ -96,6 +102,7 @@
* Defines the UID/GID for the NFC service process.
* @hide
*/
+ @UnsupportedAppUsage
public static final int NFC_UID = 1027;
/**
@@ -600,6 +607,7 @@
* Returns the identifier of this process' parent.
* @hide
*/
+ @UnsupportedAppUsage
public static final int myPpid() {
return Os.getppid();
}
@@ -658,6 +666,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public static final boolean isIsolated(int uid) {
uid = UserHandle.getAppId(uid);
return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID)
@@ -684,6 +693,7 @@
* @return the uid of the process, or -1 if the process is not running.
* @hide pending API council review
*/
+ @UnsupportedAppUsage
public static final int getUidForPid(int pid) {
String[] procStatusLabels = { "Uid:" };
long[] procStatusValues = new long[1];
@@ -698,6 +708,7 @@
* @return the parent process id of the process, or -1 if the process is not running.
* @hide
*/
+ @UnsupportedAppUsage
public static final int getParentPid(int pid) {
String[] procStatusLabels = { "PPid:" };
long[] procStatusValues = new long[1];
@@ -801,6 +812,7 @@
*
* Always sets cpusets.
*/
+ @UnsupportedAppUsage
public static final native void setProcessGroup(int pid, int group)
throws IllegalArgumentException, SecurityException;
@@ -942,6 +954,7 @@
*
* {@hide}
*/
+ @UnsupportedAppUsage
public static final native void setArgV0(String text);
/**
@@ -992,41 +1005,55 @@
public static final native void sendSignalQuiet(int pid, int signal);
/** @hide */
+ @UnsupportedAppUsage
public static final native long getFreeMemory();
/** @hide */
+ @UnsupportedAppUsage
public static final native long getTotalMemory();
/** @hide */
+ @UnsupportedAppUsage
public static final native void readProcLines(String path,
String[] reqFields, long[] outSizes);
/** @hide */
+ @UnsupportedAppUsage
public static final native int[] getPids(String path, int[] lastArray);
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_TERM_MASK = 0xff;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_ZERO_TERM = 0;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_SPACE_TERM = (int)' ';
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_TAB_TERM = (int)'\t';
/** @hide */
public static final int PROC_NEWLINE_TERM = (int) '\n';
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_COMBINE = 0x100;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_PARENS = 0x200;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_QUOTES = 0x400;
/** @hide */
public static final int PROC_CHAR = 0x800;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_OUT_STRING = 0x1000;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_OUT_LONG = 0x2000;
/** @hide */
+ @UnsupportedAppUsage
public static final int PROC_OUT_FLOAT = 0x4000;
/**
@@ -1058,14 +1085,17 @@
* @param outFloats the parsed {@code float}s from the file
* @hide
*/
+ @UnsupportedAppUsage
public static final native boolean readProcFile(String file, int[] format,
String[] outStrings, long[] outLongs, float[] outFloats);
/** @hide */
+ @UnsupportedAppUsage
public static final native boolean parseProcLine(byte[] buffer, int startIndex,
int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats);
/** @hide */
+ @UnsupportedAppUsage
public static final native int[] getPidsForCommands(String[] cmds);
/**
@@ -1076,6 +1106,7 @@
* or -1 if the value cannot be determined
* @hide
*/
+ @UnsupportedAppUsage
public static final native long getPss(int pid);
/** @hide */
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 3ee54ce..6a01e56 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -22,6 +22,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.UnsupportedAppUsage;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -355,6 +356,7 @@
*
* @return the verification result.
*/
+ @UnsupportedAppUsage
private static boolean verifyPackageCompatibility(InputStream inputStream) throws IOException {
ArrayList<String> list = new ArrayList<>();
ZipInputStream zis = new ZipInputStream(inputStream);
diff --git a/core/java/android/os/Registrant.java b/core/java/android/os/Registrant.java
index 705cc5d..8fb123a 100644
--- a/core/java/android/os/Registrant.java
+++ b/core/java/android/os/Registrant.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.os.Handler;
import android.os.Message;
@@ -24,6 +25,7 @@
/** @hide */
public class Registrant
{
+ @UnsupportedAppUsage
public
Registrant(Handler h, int what, Object obj)
{
@@ -32,6 +34,7 @@
userObj = obj;
}
+ @UnsupportedAppUsage
public void
clear()
{
@@ -39,12 +42,14 @@
userObj = null;
}
+ @UnsupportedAppUsage
public void
notifyRegistrant()
{
internalNotifyRegistrant (null, null);
}
+ @UnsupportedAppUsage
public void
notifyResult(Object result)
{
@@ -60,6 +65,7 @@
/**
* This makes a copy of @param ar
*/
+ @UnsupportedAppUsage
public void
notifyRegistrant(AsyncResult ar)
{
@@ -88,6 +94,7 @@
* NOTE: May return null if weak reference has been collected
*/
+ @UnsupportedAppUsage
public Message
messageForRegistrant()
{
diff --git a/core/java/android/os/RegistrantList.java b/core/java/android/os/RegistrantList.java
index 9ab61f5..6e562ff 100644
--- a/core/java/android/os/RegistrantList.java
+++ b/core/java/android/os/RegistrantList.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.os.Handler;
import java.util.ArrayList;
@@ -25,12 +26,14 @@
{
ArrayList registrants = new ArrayList(); // of Registrant
+ @UnsupportedAppUsage
public synchronized void
add(Handler h, int what, Object obj)
{
add(new Registrant(h, what, obj));
}
+ @UnsupportedAppUsage
public synchronized void
addUnique(Handler h, int what, Object obj)
{
@@ -39,6 +42,7 @@
add(new Registrant(h, what, obj));
}
+ @UnsupportedAppUsage
public synchronized void
add(Registrant r)
{
@@ -46,6 +50,7 @@
registrants.add(r);
}
+ @UnsupportedAppUsage
public synchronized void
removeCleared()
{
@@ -58,6 +63,7 @@
}
}
+ @UnsupportedAppUsage
public synchronized int
size()
{
@@ -79,6 +85,7 @@
}
}
+ @UnsupportedAppUsage
public /*synchronized*/ void
notifyRegistrants()
{
@@ -91,6 +98,7 @@
internalNotifyRegistrants (null, exception);
}
+ @UnsupportedAppUsage
public /*synchronized*/ void
notifyResult(Object result)
{
@@ -98,12 +106,14 @@
}
+ @UnsupportedAppUsage
public /*synchronized*/ void
notifyRegistrants(AsyncResult ar)
{
internalNotifyRegistrants(ar.result, ar.exception);
}
+ @UnsupportedAppUsage
public synchronized void
remove(Handler h)
{
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index be8f784..b377e8d 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Slog;
@@ -53,6 +54,7 @@
public class RemoteCallbackList<E extends IInterface> {
private static final String TAG = "RemoteCallbackList";
+ @UnsupportedAppUsage
/*package*/ ArrayMap<IBinder, Callback> mCallbacks
= new ArrayMap<IBinder, Callback>();
private Object[] mActiveBroadcast;
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index 4e8b971..2e673a8 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.AndroidException;
/**
@@ -54,6 +55,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public RuntimeException rethrowFromSystemServer() {
if (this instanceof DeadObjectException) {
throw new RuntimeException(new DeadSystemException());
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index a96618a..8ffafe4 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -42,12 +42,14 @@
* Determine whether SELinux is disabled or enabled.
* @return a boolean indicating whether SELinux is enabled.
*/
+ @UnsupportedAppUsage
public static final native boolean isSELinuxEnabled();
/**
* Determine whether SELinux is permissive or enforcing.
* @return a boolean indicating whether SELinux is enforcing.
*/
+ @UnsupportedAppUsage
public static final native boolean isSELinuxEnforced();
/**
@@ -91,6 +93,7 @@
* Gets the security context of the current process.
* @return a String representing the security context of the current process.
*/
+ @UnsupportedAppUsage
public static final native String getContext();
/**
@@ -98,6 +101,7 @@
* @param pid an int representing the process id to check.
* @return a String representing the security context of the given pid.
*/
+ @UnsupportedAppUsage
public static final native String getPidContext(int pid);
/**
@@ -108,6 +112,7 @@
* @param perm The permission name.
* @return a boolean indicating whether permission was granted.
*/
+ @UnsupportedAppUsage
public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm);
/**
@@ -167,6 +172,7 @@
*
* @return a boolean indicating whether the relabeling succeeded.
*/
+ @UnsupportedAppUsage
public static boolean restoreconRecursive(File file) {
try {
return native_restorecon(file.getCanonicalPath(), SELINUX_ANDROID_RESTORECON_RECURSE);
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 2966bff..9a9b030 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.ArrayMap;
import android.util.Log;
@@ -30,11 +31,13 @@
private static final String TAG = "ServiceManager";
private static final Object sLock = new Object();
+ @UnsupportedAppUsage
private static IServiceManager sServiceManager;
/**
* Cache for the "well known" services, such as WM and AM.
*/
+ @UnsupportedAppUsage
private static Map<String, IBinder> sCache = new ArrayMap<String, IBinder>();
/**
@@ -98,6 +101,7 @@
"getService()",
});
+ @UnsupportedAppUsage
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
@@ -115,6 +119,7 @@
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
+ @UnsupportedAppUsage
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
@@ -151,6 +156,7 @@
* @param name the name of the new service
* @param service the service object
*/
+ @UnsupportedAppUsage
public static void addService(String name, IBinder service) {
addService(name, service, false, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
}
@@ -164,6 +170,7 @@
* @param allowIsolated set to true to allow isolated sandboxed processes
* to access this service
*/
+ @UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated) {
addService(name, service, allowIsolated, IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT);
}
@@ -178,6 +185,7 @@
* @param dumpPriority supported dump priority levels as a bitmask
* to access this service
*/
+ @UnsupportedAppUsage
public static void addService(String name, IBinder service, boolean allowIsolated,
int dumpPriority) {
try {
@@ -191,6 +199,7 @@
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
*/
+ @UnsupportedAppUsage
public static IBinder checkService(String name) {
try {
IBinder service = sCache.get(name);
@@ -210,6 +219,7 @@
* @return an array of all currently running services, or <code>null</code> in
* case of an exception
*/
+ @UnsupportedAppUsage
public static String[] listServices() {
try {
return getIServiceManager().listServices(IServiceManager.DUMP_FLAG_PRIORITY_ALL);
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 589b8c4..b7c026c 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import java.util.ArrayList;
@@ -30,6 +31,7 @@
* Cast a Binder object into a service manager interface, generating
* a proxy if needed.
*/
+ @UnsupportedAppUsage
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
@@ -117,6 +119,7 @@
return mRemote;
}
+ @UnsupportedAppUsage
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -196,5 +199,6 @@
data.recycle();
}
+ @UnsupportedAppUsage
private IBinder mRemote;
}
diff --git a/core/java/android/os/ServiceSpecificException.java b/core/java/android/os/ServiceSpecificException.java
index 3b0f26ae..03d5d3e 100644
--- a/core/java/android/os/ServiceSpecificException.java
+++ b/core/java/android/os/ServiceSpecificException.java
@@ -15,6 +15,7 @@
*/
package android.os;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
/**
@@ -34,7 +35,7 @@
public class ServiceSpecificException extends RuntimeException {
public final int errorCode;
- public ServiceSpecificException(int errorCode, String message) {
+ public ServiceSpecificException(int errorCode, @Nullable String message) {
super(message);
this.errorCode = errorCode;
}
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 395485b..57a8801 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -156,6 +157,7 @@
*
* @hide Exposed for native ASharedMemory_dupFromJava()
*/
+ @UnsupportedAppUsage
public int getFd() {
return mFileDescriptor.getInt$();
}
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index 5228d6d..2fe8726 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.Slog;
import com.android.internal.util.FastPrintWriter;
@@ -304,6 +305,7 @@
}
}
+ @UnsupportedAppUsage
public String peekNextArg() {
if (mCurArgData != null) {
return mCurArgData;
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index 4e0b238..881d0b4 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStatVfs;
@@ -25,6 +26,7 @@
* wrapper for Unix statvfs().
*/
public class StatFs {
+ @UnsupportedAppUsage
private StructStatVfs mStat;
/**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f0b83d8..94cca30 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
@@ -421,6 +422,7 @@
/** The default, lax policy which doesn't catch anything. */
public static final ThreadPolicy LAX = new ThreadPolicy(0, null, null);
+ @UnsupportedAppUsage
final @ThreadPolicyMask int mask;
final OnThreadViolationListener mListener;
final Executor mCallbackExecutor;
@@ -713,6 +715,7 @@
/** The default, lax policy which doesn't catch anything. */
public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP, null, null);
+ @UnsupportedAppUsage
final @VmPolicyMask int mask;
final OnVmViolationListener mListener;
final Executor mCallbackExecutor;
@@ -758,6 +761,7 @@
* </pre>
*/
public static final class Builder {
+ @UnsupportedAppUsage
private @VmPolicyMask int mMask;
private OnVmViolationListener mListener;
private Executor mExecutor;
@@ -1208,6 +1212,7 @@
* @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
* @hide
*/
+ @UnsupportedAppUsage
public static @ThreadPolicyMask int getThreadPolicyMask() {
final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (policy instanceof AndroidBlockGuardPolicy) {
@@ -1412,6 +1417,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void enableDeathOnFileUriExposure() {
sVmPolicy =
new VmPolicy(
@@ -1429,6 +1435,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void disableDeathOnFileUriExposure() {
sVmPolicy =
new VmPolicy(
@@ -1440,6 +1447,7 @@
sVmPolicy.mCallbackExecutor);
}
+ @UnsupportedAppUsage
private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
new ThreadLocal<ArrayList<ViolationInfo>>() {
@Override
@@ -2051,6 +2059,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
onVmPolicyViolation(new WebViewMethodCalledOnWrongThreadViolation(originStack));
}
@@ -2155,6 +2164,7 @@
}
// Map from VM violation fingerprint to uptime millis.
+ @UnsupportedAppUsage
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>();
/** @hide */
@@ -2280,6 +2290,7 @@
* Binder for its current (native) thread-local policy value and synchronize it to libcore's
* (Java) thread-local policy value.
*/
+ @UnsupportedAppUsage
private static void onBinderStrictModePolicyChange(@ThreadPolicyMask int newPolicy) {
setBlockGuardPolicy(newPolicy);
}
@@ -2316,6 +2327,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public void finish() {
ThreadSpanState state = mContainerState;
synchronized (state) {
@@ -2387,6 +2399,7 @@
}
};
+ @UnsupportedAppUsage
private static Singleton<IWindowManager> sWindowManager =
new Singleton<IWindowManager>() {
protected IWindowManager create() {
@@ -2407,6 +2420,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static Span enterCriticalSpan(String name) {
if (Build.IS_USER) {
return NO_OP_SPAN;
@@ -2516,6 +2530,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static void incrementExpectedActivityCount(Class klass) {
if (klass == null) {
return;
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index b2541663..e695a1b 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.NonNull;
+import android.annotation.UnsupportedAppUsage;
import android.app.IAlarmManager;
import android.content.Context;
import android.util.Slog;
@@ -104,6 +105,7 @@
/**
* This class is uninstantiable.
*/
+ @UnsupportedAppUsage
private SystemClock() {
// This space intentionally left blank.
}
@@ -241,6 +243,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
@CriticalNative
public static native long currentThreadTimeMicro();
@@ -251,6 +254,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
@CriticalNative
public static native long currentTimeMicro();
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index cbcf600..edfdda8bb 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.MutableInt;
@@ -51,11 +52,13 @@
* uses reflection to read this whenever text is selected (http://b/36095274).
* @hide
*/
+ @UnsupportedAppUsage
public static final int PROP_NAME_MAX = Integer.MAX_VALUE;
/** @hide */
public static final int PROP_VALUE_MAX = 91;
+ @UnsupportedAppUsage
@GuardedBy("sChangeCallbacks")
private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
@@ -83,9 +86,11 @@
}
}
+ @UnsupportedAppUsage
private static native String native_get(String key);
private static native String native_get(String key, String def);
private static native int native_get_int(String key, int def);
+ @UnsupportedAppUsage
private static native long native_get_long(String key, long def);
private static native boolean native_get_boolean(String key, boolean def);
private static native void native_set(String key, String def);
@@ -180,6 +185,7 @@
* @throws IllegalArgumentException if the {@code val} exceeds 91 characters
* @hide
*/
+ @UnsupportedAppUsage
public static void set(@NonNull String key, @Nullable String val) {
if (val != null && !val.startsWith("ro.") && val.length() > PROP_VALUE_MAX) {
throw new IllegalArgumentException("value of system property '" + key
@@ -196,6 +202,7 @@
* changes.
* @hide
*/
+ @UnsupportedAppUsage
public static void addChangeCallback(@NonNull Runnable callback) {
synchronized (sChangeCallbacks) {
if (sChangeCallbacks.size() == 0) {
@@ -233,6 +240,7 @@
* Notifies listeners that a system property has changed
* @hide
*/
+ @UnsupportedAppUsage
public static void reportSyspropChanged() {
native_report_sysprop_change();
}
@@ -258,6 +266,7 @@
}
}
+ @UnsupportedAppUsage
private SystemProperties() {
}
}
diff --git a/core/java/android/os/SystemService.java b/core/java/android/os/SystemService.java
index 41e7546..968c761 100644
--- a/core/java/android/os/SystemService.java
+++ b/core/java/android/os/SystemService.java
@@ -18,6 +18,7 @@
import com.google.android.collect.Maps;
+import android.annotation.UnsupportedAppUsage;
import java.util.HashMap;
import java.util.concurrent.TimeoutException;
@@ -58,11 +59,13 @@
}
/** Request that the init daemon start a named service. */
+ @UnsupportedAppUsage
public static void start(String name) {
SystemProperties.set("ctl.start", name);
}
/** Request that the init daemon stop a named service. */
+ @UnsupportedAppUsage
public static void stop(String name) {
SystemProperties.set("ctl.stop", name);
}
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index c989197..4af514a 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.media.AudioAttributes;
import android.util.Log;
@@ -31,10 +32,12 @@
private final IVibratorService mService;
private final Binder mToken = new Binder();
+ @UnsupportedAppUsage
public SystemVibrator() {
mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
}
+ @UnsupportedAppUsage
public SystemVibrator(Context context) {
super(context);
mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 68d6d85..1456a73 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.NonNull;
+import android.annotation.UnsupportedAppUsage;
import com.android.internal.os.Zygote;
@@ -52,6 +53,7 @@
/** @hide */
public static final long TRACE_TAG_INPUT = 1L << 2;
/** @hide */
+ @UnsupportedAppUsage
public static final long TRACE_TAG_VIEW = 1L << 3;
/** @hide */
public static final long TRACE_TAG_WEBVIEW = 1L << 4;
@@ -70,6 +72,7 @@
/** @hide */
public static final long TRACE_TAG_HAL = 1L << 11;
/** @hide */
+ @UnsupportedAppUsage
public static final long TRACE_TAG_APP = 1L << 12;
/** @hide */
public static final long TRACE_TAG_RESOURCES = 1L << 13;
@@ -104,10 +107,12 @@
private static final int MAX_SECTION_NAME_LEN = 127;
// Must be volatile to avoid word tearing.
+ @UnsupportedAppUsage
private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
private static int sZygoteDebugFlags = 0;
+ @UnsupportedAppUsage
private static native long nativeGetEnabledTags();
private static native void nativeSetAppTracingAllowed(boolean allowed);
private static native void nativeSetTracingEnabled(boolean allowed);
@@ -171,6 +176,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static boolean isTagEnabled(long traceTag) {
long tags = sEnabledTags;
if (tags == TRACE_TAG_NOT_READY) {
@@ -188,6 +194,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void traceCounter(long traceTag, String counterName, int counterValue) {
if (isTagEnabled(traceTag)) {
nativeTraceCounter(traceTag, counterName, counterValue);
@@ -200,6 +207,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void setAppTracingAllowed(boolean allowed) {
nativeSetAppTracingAllowed(allowed);
@@ -235,6 +243,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void traceBegin(long traceTag, String methodName) {
if (isTagEnabled(traceTag)) {
nativeTraceBegin(traceTag, methodName);
@@ -249,6 +258,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void traceEnd(long traceTag) {
if (isTagEnabled(traceTag)) {
nativeTraceEnd(traceTag);
@@ -268,6 +278,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void asyncTraceBegin(long traceTag, String methodName, int cookie) {
if (isTagEnabled(traceTag)) {
nativeAsyncTraceBegin(traceTag, methodName, cookie);
@@ -285,6 +296,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public static void asyncTraceEnd(long traceTag, String methodName, int cookie) {
if (isTagEnabled(traceTag)) {
nativeAsyncTraceEnd(traceTag, methodName, cookie);
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index 69a3922..dc98c42 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.util.Log;
import java.util.ArrayList;
@@ -49,6 +50,7 @@
private static native void nativeAddMatch(String match);
private static native void nativeRemoveMatch(String match);
+ @UnsupportedAppUsage
public UEventObserver() {
}
@@ -93,6 +95,7 @@
* are expensive to parse. For example, some devices may send one netlink message
* for each vsync period.
*/
+ @UnsupportedAppUsage
public final void startObserving(String match) {
if (match == null || match.isEmpty()) {
throw new IllegalArgumentException("match substring must be non-empty");
@@ -107,6 +110,7 @@
* This process's UEvent thread will never call onUEvent() on this
* UEventObserver after this call. Repeated calls have no effect.
*/
+ @UnsupportedAppUsage
public final void stopObserving() {
final UEventThread t = peekThread();
if (t != null) {
@@ -118,6 +122,7 @@
* Subclasses of UEventObserver should override this method to handle
* UEvents.
*/
+ @UnsupportedAppUsage
public abstract void onUEvent(UEvent event);
/**
@@ -146,10 +151,12 @@
}
}
+ @UnsupportedAppUsage
public String get(String key) {
return mMap.get(key);
}
+ @UnsupportedAppUsage
public String get(String key, String defaultValue) {
String result = mMap.get(key);
return (result == null ? defaultValue : result);
diff --git a/core/java/android/os/UpdateLock.java b/core/java/android/os/UpdateLock.java
index 4060326..ea273ce 100644
--- a/core/java/android/os/UpdateLock.java
+++ b/core/java/android/os/UpdateLock.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.util.Log;
@@ -50,6 +51,7 @@
* locker releases theirs. The broadcast is sticky but is sent only to
* registered receivers.
*/
+ @UnsupportedAppUsage
public static final String UPDATE_LOCK_CHANGED = "android.os.UpdateLock.UPDATE_LOCK_CHANGED";
/**
@@ -58,6 +60,7 @@
* update operation. True means that updates are okay right now; false indicates
* that perhaps later would be a better time.
*/
+ @UnsupportedAppUsage
public static final String NOW_IS_CONVENIENT = "nowisconvenient";
/**
@@ -66,6 +69,7 @@
* in the System.currentTimeMillis() time base, which may be non-monotonic especially
* around reboots.
*/
+ @UnsupportedAppUsage
public static final String TIMESTAMP = "timestamp";
/**
@@ -90,6 +94,7 @@
/**
* Is this lock currently held?
*/
+ @UnsupportedAppUsage
public boolean isHeld() {
synchronized (mToken) {
return mHeld;
@@ -99,6 +104,7 @@
/**
* Acquire an update lock.
*/
+ @UnsupportedAppUsage
public void acquire() {
if (DEBUG) {
Log.v(TAG, "acquire() : " + this, new RuntimeException("here"));
@@ -125,6 +131,7 @@
/**
* Release this update lock.
*/
+ @UnsupportedAppUsage
public void release() {
if (DEBUG) Log.v(TAG, "release() : " + this, new RuntimeException("here"));
checkService();
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 286185b..b121234 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.annotation.UserIdInt;
import java.io.PrintWriter;
@@ -33,9 +34,11 @@
/**
* @hide Range of uids allocated for a user.
*/
+ @UnsupportedAppUsage
public static final int PER_USER_RANGE = 100000;
/** @hide A user id to indicate all users on the device */
+ @UnsupportedAppUsage
public static final @UserIdInt int USER_ALL = -1;
/** @hide A user handle to indicate all users on the device */
@@ -44,6 +47,7 @@
public static final @NonNull UserHandle ALL = new UserHandle(USER_ALL);
/** @hide A user id to indicate the currently active user */
+ @UnsupportedAppUsage
public static final @UserIdInt int USER_CURRENT = -2;
/** @hide A user handle to indicate the current user of the device */
@@ -54,11 +58,13 @@
/** @hide A user id to indicate that we would like to send to the current
* user, but if this is calling from a user process then we will send it
* to the caller's user instead of failing with a security exception */
+ @UnsupportedAppUsage
public static final @UserIdInt int USER_CURRENT_OR_SELF = -3;
/** @hide A user handle to indicate that we would like to send to the current
* user, but if this is calling from a user process then we will send it
* to the caller's user instead of failing with a security exception */
+ @UnsupportedAppUsage
public static final @NonNull UserHandle CURRENT_OR_SELF = new UserHandle(USER_CURRENT_OR_SELF);
/** @hide An undefined user id */
@@ -69,6 +75,7 @@
* @deprecated Consider using either {@link UserHandle#USER_SYSTEM} constant or
* check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
*/
+ @UnsupportedAppUsage
@Deprecated
public static final @UserIdInt int USER_OWNER = 0;
@@ -77,13 +84,16 @@
* @deprecated Consider using either {@link UserHandle#SYSTEM} constant or
* check the target user's flag {@link android.content.pm.UserInfo#isAdmin}.
*/
+ @UnsupportedAppUsage
@Deprecated
public static final @NonNull UserHandle OWNER = new UserHandle(USER_OWNER);
/** @hide A user id constant to indicate the "system" user of the device */
+ @UnsupportedAppUsage
public static final @UserIdInt int USER_SYSTEM = 0;
/** @hide A user serial constant to indicate the "system" user of the device */
+ @UnsupportedAppUsage
public static final int USER_SERIAL_SYSTEM = 0;
/** @hide A user handle to indicate the "system" user of the device */
@@ -95,21 +105,29 @@
* @hide Enable multi-user related side effects. Set this to false if
* there are problems with single user use-cases.
*/
+ @UnsupportedAppUsage
public static final boolean MU_ENABLED = true;
/** @hide */
+ @UnsupportedAppUsage
public static final int ERR_GID = -1;
/** @hide */
+ @UnsupportedAppUsage
public static final int AID_ROOT = android.os.Process.ROOT_UID;
/** @hide */
+ @UnsupportedAppUsage
public static final int AID_APP_START = android.os.Process.FIRST_APPLICATION_UID;
/** @hide */
+ @UnsupportedAppUsage
public static final int AID_APP_END = android.os.Process.LAST_APPLICATION_UID;
/** @hide */
+ @UnsupportedAppUsage
public static final int AID_SHARED_GID_START = android.os.Process.FIRST_SHARED_APPLICATION_GID;
/** @hide */
+ @UnsupportedAppUsage
public static final int AID_CACHE_GID_START = android.os.Process.FIRST_APPLICATION_CACHE_GID;
+ @UnsupportedAppUsage
final int mHandle;
/**
@@ -129,6 +147,7 @@
* @return whether the appId is the same for both uids
* @hide
*/
+ @UnsupportedAppUsage
public static boolean isSameApp(int uid1, int uid2) {
return getAppId(uid1) == getAppId(uid2);
}
@@ -137,6 +156,7 @@
* Whether a UID is an "isolated" UID.
* @hide
*/
+ @UnsupportedAppUsage
public static boolean isIsolated(int uid) {
if (uid > 0) {
return Process.isIsolated(uid);
@@ -186,6 +206,7 @@
* Returns the user id for a given uid.
* @hide
*/
+ @UnsupportedAppUsage
public static @UserIdInt int getUserId(int uid) {
if (MU_ENABLED) {
return uid / PER_USER_RANGE;
@@ -195,6 +216,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static @UserIdInt int getCallingUserId() {
return getUserId(Binder.getCallingUid());
}
@@ -214,6 +236,7 @@
* Returns the uid that is composed from the userId and the appId.
* @hide
*/
+ @UnsupportedAppUsage
public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {
if (MU_ENABLED) {
return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);
@@ -260,6 +283,7 @@
* Returns the app id for a given shared app gid. Returns -1 if the ID is invalid.
* @hide
*/
+ @UnsupportedAppUsage
public static @AppIdInt int getAppIdFromSharedAppGid(int gid) {
final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID
- Process.FIRST_SHARED_APPLICATION_GID;
@@ -405,6 +429,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public UserHandle(int h) {
mHandle = h;
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 185df5e..9c9829f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -70,6 +70,7 @@
public class UserManager {
private static final String TAG = "UserManager";
+ @UnsupportedAppUsage
private final IUserManager mService;
private final Context mContext;
@@ -810,6 +811,7 @@
* @see #getUserRestrictions()
* @hide
*/
+ @UnsupportedAppUsage
public static final String DISALLOW_RECORD_AUDIO = "no_record_audio";
/**
@@ -1238,6 +1240,7 @@
}
/** @hide */
+ @UnsupportedAppUsage
public static UserManager get(Context context) {
return (UserManager) context.getSystemService(Context.USER_SERVICE);
}
@@ -1341,6 +1344,7 @@
* @return the user handle of this process.
* @hide
*/
+ @UnsupportedAppUsage
public @UserIdInt int getUserHandle() {
return UserHandle.myUserId();
}
@@ -1348,12 +1352,16 @@
/**
* Returns the user name of the user making this call. This call is only
* available to applications on the system image; it requires the
- * MANAGE_USERS permission.
+ * {@code android.permission.MANAGE_USERS} or {@code android.permission.GET_ACCOUNTS_PRIVILEGED}
+ * permissions.
* @return the user name
*/
public String getUserName() {
- UserInfo user = getUserInfo(getUserHandle());
- return user == null ? "" : user.name;
+ try {
+ return mService.getUserName();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
}
/**
@@ -1428,6 +1436,7 @@
* Returns whether the provided user is an admin user. There can be more than one admin
* user.
*/
+ @UnsupportedAppUsage
public boolean isUserAdmin(@UserIdInt int userId) {
UserInfo user = getUserInfo(userId);
return user != null && user.isAdmin();
@@ -1437,6 +1446,7 @@
* @hide
* @deprecated Use {@link #isRestrictedProfile()}
*/
+ @UnsupportedAppUsage
@Deprecated
public boolean isLinkedUser() {
return isRestrictedProfile();
@@ -1460,6 +1470,24 @@
}
/**
+ * Check if a user is a restricted profile. Restricted profiles may have a reduced number of
+ * available apps, app restrictions, and account restrictions.
+ *
+ * @param user the user to check
+ * @return whether the user is a restricted profile.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public boolean isRestrictedProfile(@NonNull UserHandle user) {
+ try {
+ return mService.getUserInfo(user.getIdentifier()).isRestricted();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks if specified user can have restricted profile.
* @hide
*/
@@ -1490,6 +1518,7 @@
* @return whether user is a guest user.
* @hide
*/
+ @UnsupportedAppUsage
public boolean isGuestUser(int id) {
UserInfo user = getUserInfo(id);
return user != null && user.isGuest();
@@ -1699,6 +1728,7 @@
}
/** {@hide} */
+ @UnsupportedAppUsage
public boolean isUserUnlocked(@UserIdInt int userId) {
try {
return mService.isUserUnlocked(userId);
@@ -1727,6 +1757,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public long getUserStartRealtime() {
try {
return mService.getUserStartRealtime();
@@ -1741,6 +1772,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public long getUserUnlockRealtime() {
try {
return mService.getUserUnlockRealtime();
@@ -1756,6 +1788,7 @@
* @return the UserInfo object for a specific user.
* @hide
*/
+ @UnsupportedAppUsage
public UserInfo getUserInfo(@UserIdInt int userHandle) {
try {
return mService.getUserInfo(userHandle);
@@ -1836,6 +1869,7 @@
* @param restrictionKey the string key representing the restriction
* @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
*/
+ @UnsupportedAppUsage
public boolean hasBaseUserRestriction(String restrictionKey, UserHandle userHandle) {
try {
return mService.hasBaseUserRestriction(restrictionKey, userHandle.getIdentifier());
@@ -1918,6 +1952,7 @@
* @param restrictionKey the string key representing the restriction
* @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
*/
+ @UnsupportedAppUsage
public boolean hasUserRestriction(String restrictionKey, UserHandle userHandle) {
try {
return mService.hasUserRestriction(restrictionKey,
@@ -1978,6 +2013,7 @@
* @return the UserInfo object for the created user, or null if the user could not be created.
* @hide
*/
+ @UnsupportedAppUsage
public UserInfo createUser(String name, int flags) {
UserInfo user = null;
try {
@@ -2026,6 +2062,7 @@
* could not be created.
* @hide
*/
+ @UnsupportedAppUsage
public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {
return createProfileForUser(name, flags, userHandle, null);
}
@@ -2314,6 +2351,7 @@
* @return the list of users that exist on the device.
* @hide
*/
+ @UnsupportedAppUsage
public List<UserInfo> getUsers() {
try {
return mService.getUsers(false);
@@ -2439,6 +2477,7 @@
* @return the list of profiles.
* @hide
*/
+ @UnsupportedAppUsage
public List<UserInfo> getProfiles(@UserIdInt int userHandle) {
try {
return mService.getProfiles(userHandle, false /* enabledOnly */);
@@ -2472,6 +2511,7 @@
* @return the list of profiles.
* @hide
*/
+ @UnsupportedAppUsage
public List<UserInfo> getEnabledProfiles(@UserIdInt int userHandle) {
try {
return mService.getProfiles(userHandle, true /* enabledOnly */);
@@ -2519,6 +2559,7 @@
* @see #getProfileIds(int, boolean)
* @hide
*/
+ @UnsupportedAppUsage
public int[] getProfileIdsWithDisabled(@UserIdInt int userId) {
return getProfileIds(userId, false /* enabledOnly */);
}
@@ -2552,6 +2593,7 @@
*
* @hide
*/
+ @UnsupportedAppUsage
public UserInfo getProfileParent(@UserIdInt int userHandle) {
try {
return mService.getProfileParent(userHandle);
@@ -2721,6 +2763,7 @@
* @return the list of users that were created.
* @hide
*/
+ @UnsupportedAppUsage
public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
try {
return mService.getUsers(excludeDying);
@@ -2735,6 +2778,7 @@
* @param userHandle the integer handle of the user, where 0 is the primary user.
* @hide
*/
+ @UnsupportedAppUsage
public boolean removeUser(@UserIdInt int userHandle) {
try {
return mService.removeUser(userHandle);
@@ -2840,6 +2884,7 @@
* @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default.
* @hide
*/
+ @UnsupportedAppUsage
public Bitmap getUserIcon(@UserIdInt int userHandle) {
try {
ParcelFileDescriptor fd = mService.getUserIcon(userHandle);
@@ -2861,14 +2906,16 @@
/**
* Returns a Bitmap for the calling user's photo.
- * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS}
+ * or {@link android.Manifest.permission#GET_ACCOUNTS_PRIVILEGED} permissions.
*
* @return a {@link Bitmap} of the user's photo, or null if there's no photo.
* @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default.
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED})
public @Nullable Bitmap getUserIcon() {
return getUserIcon(getUserHandle());
}
@@ -2879,6 +2926,7 @@
* @hide
* @return a value greater than or equal to 1
*/
+ @UnsupportedAppUsage
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
@@ -2934,6 +2982,7 @@
/**
* @hide
*/
+ @UnsupportedAppUsage
public static boolean isDeviceInDemoMode(Context context) {
return Settings.Global.getInt(context.getContentResolver(),
Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
@@ -2946,6 +2995,7 @@
* @return a serial number associated with that user, or -1 if the userHandle is not valid.
* @hide
*/
+ @UnsupportedAppUsage
public int getUserSerialNumber(@UserIdInt int userHandle) {
try {
return mService.getUserSerialNumber(userHandle);
@@ -2963,6 +3013,7 @@
* is not valid.
* @hide
*/
+ @UnsupportedAppUsage
public @UserIdInt int getUserHandle(int userSerialNumber) {
try {
return mService.getUserHandle(userSerialNumber);
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 226d1d0..28909c8 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
import android.content.Context;
import android.media.AudioAttributes;
@@ -85,6 +86,7 @@
/**
* @hide to prevent subclassing from outside of the framework
*/
+ @UnsupportedAppUsage
public Vibrator() {
mPackageName = ActivityThread.currentPackageName();
final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 9980ade..0b4a561 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -3,6 +3,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.WorkSourceProto;
import android.provider.Settings;
@@ -24,8 +25,11 @@
static final String TAG = "WorkSource";
static final boolean DEBUG = false;
+ @UnsupportedAppUsage
int mNum;
+ @UnsupportedAppUsage
int[] mUids;
+ @UnsupportedAppUsage
String[] mNames;
private ArrayList<WorkChain> mChains;
@@ -103,6 +107,7 @@
mChains = null;
}
+ @UnsupportedAppUsage
WorkSource(Parcel in) {
mNum = in.readInt();
mUids = in.createIntArray();
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 6f0a1f2..40238d2 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.content.pm.ApplicationInfo;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
@@ -41,10 +42,12 @@
import java.util.UUID;
/*package*/ class ZygoteStartFailedEx extends Exception {
+ @UnsupportedAppUsage
ZygoteStartFailedEx(String s) {
super(s);
}
+ @UnsupportedAppUsage
ZygoteStartFailedEx(Throwable cause) {
super(cause);
}
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index 71eda19..a92e28a 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -37,11 +37,13 @@
* by the logging itself. It can be substantial.
* <p>
* <b>Battery Usage</b><br>
- * The statistics related to power (battery) usage are recorded since the device
- * was last unplugged. It is expected that applications schedule more work to do
- * while the device is plugged in (e.g. using {@link android.app.job.JobScheduler
- * JobScheduler}), and while that can affect charging rates, it is still preferable
- * to actually draining the battery.
+ * Since Android version {@link android.os.Build.VERSION_CODES#Q}, the statistics related to power
+ * (battery) usage are recorded since the device was last considered fully charged (for previous
+ * versions, it is instead since the device was last unplugged).
+ * It is expected that applications schedule more work to do while the device is
+ * plugged in (e.g. using {@link android.app.job.JobScheduler JobScheduler}), and
+ * while that can affect charging rates, it is still preferable to actually draining
+ * the battery.
*/
@SystemService(Context.SYSTEM_HEALTH_SERVICE)
public class SystemHealthManager {
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 27e3914..3e60d51 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -16,6 +16,8 @@
package android.os.storage;
+import static android.content.ContentResolver.DEPRECATE_DATA_PREFIX;
+
import android.annotation.BytesLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -30,6 +32,7 @@
import android.annotation.WorkerThread;
import android.app.Activity;
import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -1139,6 +1142,12 @@
if (file == null) {
return null;
}
+ final String path = file.getAbsolutePath();
+ if (path.startsWith(DEPRECATE_DATA_PREFIX)) {
+ final Uri uri = ContentResolver.translateDeprecatedDataPath(path);
+ return AppGlobals.getInitialApplication().getSystemService(StorageManager.class)
+ .getStorageVolume(uri);
+ }
try {
file = file.getCanonicalFile();
} catch (IOException ignored) {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 046ed2f..4322a59 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -78,6 +78,15 @@
"activity_manager_native_boot";
/**
+ * Namespace for all app compat related features. These features will be applied
+ * immediately upon change.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_APP_COMPAT = "app_compat";
+
+ /**
* Namespace for AttentionManagerService related features.
*
* @hide
@@ -163,7 +172,24 @@
public static final String NAMESPACE_NETD_NATIVE = "netd_native";
/**
- * Namespace for all runtime related features.
+ * Namespace for Rollback flags that are applied immediately.
+ *
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final String NAMESPACE_ROLLBACK = "rollback";
+
+ /**
+ * Namespace for Rollback flags that are applied after a reboot.
+ *
+ * @hide
+ */
+ @SystemApi @TestApi
+ public static final String NAMESPACE_ROLLBACK_BOOT = "rollback_boot";
+
+ /**
+ * Namespace for all runtime related features that don't require a reboot to become active.
+ * There are no feature flags using NAMESPACE_RUNTIME.
*
* @hide
*/
@@ -171,7 +197,9 @@
public static final String NAMESPACE_RUNTIME = "runtime";
/**
- * Namespace for all runtime native related features.
+ * Namespace for all runtime related features that require system properties for accessing
+ * the feature flags from C++ or Java language code. One example is the app image startup
+ * cache feature use_app_image_startup_cache.
*
* @hide
*/
@@ -188,6 +216,23 @@
public static final String NAMESPACE_RUNTIME_NATIVE_BOOT = "runtime_native_boot";
/**
+ * Namespace for system scheduler related features. These features will be applied
+ * immediately upon change.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_SCHEDULER = "scheduler";
+
+ /**
+ * Namespace for storage-related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_STORAGE = "storage";
+
+ /**
* Namespace for System UI related features.
*
* @hide
@@ -196,6 +241,14 @@
public static final String NAMESPACE_SYSTEMUI = "systemui";
/**
+ * Telephony related properties.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_TELEPHONY = "telephony";
+
+ /**
* Namespace for TextClassifier related features.
*
* @hide
@@ -240,7 +293,6 @@
*
* @hide
*/
- @SystemApi
public interface Telephony {
String NAMESPACE = "telephony";
/**
@@ -257,86 +309,6 @@
String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
}
- /**
- * Namespace for Rollback.
- *
- * @hide
- */
- @SystemApi @TestApi
- public interface Rollback {
-
- /**
- * Namespace for flags that can be changed immediately after becoming available on device.
- */
- String NAMESPACE = "rollback";
-
- /**
- * Namespace for flags that can be changed only after reboot.
- */
- String BOOT_NAMESPACE = "rollback_boot";
-
- /**
- * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
- * rollback within that period, the install will proceed without rollback enabled.
- *
- * <p>If flag value is negative, the default value will be assigned.
- *
- * Flag type: {@code long}
- * Namespace: Rollback.NAMESPACE
- */
- String ENABLE_ROLLBACK_TIMEOUT = "enable_rollback_timeout";
-
- /**
- * Lifetime duration of rollback packages in millis. A rollback will be available for
- * at most that duration of time after a package is installed with
- * {@link PackageInstaller.SessionParams#setEnableRollback()}.
- *
- * <p>If flag value is negative, the default value will be assigned.
- *
- * @see RollbackManager
- *
- * Flag type: {@code long}
- * Namespace: Rollback.BOOT_NAMESPACE
- */
- String ROLLBACK_LIFETIME_IN_MILLIS = "rollback_lifetime_in_millis";
- }
-
- /**
- * Namespace for storage-related features.
- *
- * @hide
- */
- @SystemApi
- public interface Storage {
- String NAMESPACE = "storage";
-
- /**
- * If {@code 1}, enables the isolated storage feature. If {@code -1},
- * disables the isolated storage feature. If {@code 0}, uses the default
- * value from the build system.
- */
- String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
- }
-
- /**
- * Namespace for system scheduler related features. These features will be applied
- * immediately upon change.
- *
- * @hide
- */
- @SystemApi
- public interface Scheduler {
- String NAMESPACE = "scheduler";
-
- /**
- * Flag for enabling fast metrics collection in system scheduler.
- * A flag value of '' or '0' means the fast metrics collection is not
- * enabled. Otherwise fast metrics collection is enabled and flag value
- * is the order id.
- */
- String ENABLE_FAST_METRICS_COLLECTION = "enable_fast_metrics_collection";
- }
-
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 2814474..8f772d4 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -641,37 +641,22 @@
continue;
}
try {
- Font font = null;
- try {
- font = new Font.Builder(buffer)
+ final Font font = new Font.Builder(buffer)
.setWeight(fontInfo.getWeight())
.setSlant(fontInfo.isItalic()
? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT)
.setTtcIndex(fontInfo.getTtcIndex())
.setFontVariationSettings(fontInfo.getAxes())
.build();
- } catch (IllegalArgumentException e) {
- // The exception happens if the unsupported font is passed. We suppress this
- // exception and just ignore this font here since there is no way of
- // resolving this issue by users during inflating layout.
- Log.w(TAG, "Ignoring font file since failed to create font object."
- + " The font file is not supported on this platform.");
- continue;
- }
if (familyBuilder == null) {
familyBuilder = new FontFamily.Builder(font);
} else {
- try {
- familyBuilder.addFont(font);
- } catch (IllegalArgumentException e) {
- // The exception happens if the same style font is added to the family.
- // We suppress this exception and just ignore this font here since there is
- // no way of resolving this issue by users during inflating layout.
- Log.w(TAG,
- "Ignoring font file since the same style font is already added.");
- continue;
- }
+ familyBuilder.addFont(font);
}
+ } catch (IllegalArgumentException e) {
+ // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion
+ // thrown by native code and returns null.
+ return null;
} catch (IOException e) {
continue;
}
diff --git a/core/java/android/provider/SearchIndexablesProvider.java b/core/java/android/provider/SearchIndexablesProvider.java
index 1549c45..d505f02 100644
--- a/core/java/android/provider/SearchIndexablesProvider.java
+++ b/core/java/android/provider/SearchIndexablesProvider.java
@@ -25,6 +25,7 @@
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.net.Uri;
+import android.util.Log;
/**
* Base class for a search indexable provider. Such provider offers data to be indexed either
@@ -112,19 +113,26 @@
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
- switch (mMatcher.match(uri)) {
- case MATCH_RES_CODE:
- return queryXmlResources(null);
- case MATCH_RAW_CODE:
- return queryRawData(null);
- case MATCH_NON_INDEXABLE_KEYS_CODE:
- return queryNonIndexableKeys(null);
- case MATCH_SITE_MAP_PAIRS_CODE:
- return querySiteMapPairs();
- case MATCH_SLICE_URI_PAIRS_CODE:
- return querySliceUriPairs();
- default:
- throw new UnsupportedOperationException("Unknown Uri " + uri);
+ try {
+ switch (mMatcher.match(uri)) {
+ case MATCH_RES_CODE:
+ return queryXmlResources(null);
+ case MATCH_RAW_CODE:
+ return queryRawData(null);
+ case MATCH_NON_INDEXABLE_KEYS_CODE:
+ return queryNonIndexableKeys(null);
+ case MATCH_SITE_MAP_PAIRS_CODE:
+ return querySiteMapPairs();
+ case MATCH_SLICE_URI_PAIRS_CODE:
+ return querySliceUriPairs();
+ default:
+ throw new UnsupportedOperationException("Unknown Uri " + uri);
+ }
+ } catch (UnsupportedOperationException e) {
+ throw e;
+ } catch (Exception e) {
+ Log.e(TAG, "Provider querying exception:", e);
+ return null;
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index df5da6c..7c80a0b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1696,6 +1696,19 @@
public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE =
"android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
+ /**
+ * Activity Action: Show screen that let user manage how Android handles URL resolution.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
+
// End of Intent actions for Settings
/**
@@ -5594,11 +5607,23 @@
*
* @hide
*/
+ @SystemApi
public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
private static final Validator ODI_CAPTIONS_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
/**
+ * Setting to indicate that on device captions cannot be shown because the app
+ * which is currently playing media had opted out.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String ODI_CAPTIONS_OPTED_OUT = "odi_captions_opted_out";
+
+ private static final Validator ODI_CAPTIONS_OPTED_OUT_VALIDATOR = BOOLEAN_VALIDATOR;
+
+ /**
* On Android 8.0 (API level 26) and higher versions of the platform,
* a 64-bit number (expressed as a hexadecimal string), unique to
* each combination of app-signing key, user, and device.
@@ -8965,6 +8990,7 @@
VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
+ VALIDATORS.put(ODI_CAPTIONS_OPTED_OUT, ODI_CAPTIONS_OPTED_OUT_VALIDATOR);
}
/**
@@ -9053,7 +9079,6 @@
* @return true if the provider is enabled
*
* @deprecated use {@link LocationManager#isProviderEnabled(String)}
- * @removed no longer supported
*/
@Deprecated
public static boolean isLocationProviderEnabled(ContentResolver cr, String provider) {
@@ -9063,12 +9088,12 @@
}
/**
- * Thread-safe method for enabling or disabling a single location provider.
+ * Thread-safe method for enabling or disabling a single location provider. This will have
+ * no effect on Android Q and above.
* @param cr the content resolver to use
* @param provider the location provider to enable or disable
* @param enabled true if the provider should be enabled
* @deprecated This API is deprecated
- * @removed no longer supported
*/
@Deprecated
public static void setLocationProviderEnabled(ContentResolver cr,
@@ -12586,8 +12611,9 @@
/**
* Battery level [1-100] at which low power mode automatically turns on.
- * Pre-Q If 0, it will not automatically turn on. Q and newer it will only automatically
- * turn on if the {@link #AUTOMATIC_POWER_SAVER_MODE} setting is also set to
+ * If 0, it will not automatically turn on. For Q and newer, it will only automatically
+ * turn on if the value is greater than 0 and the {@link #AUTOMATIC_POWER_SAVER_MODE}
+ * setting is also set to
* {@link android.os.PowerManager.AutoPowerSaverMode#POWER_SAVER_MODE_PERCENTAGE}.
*
* @see #AUTOMATIC_POWER_SAVER_MODE
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index cd54930..96b861b 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -30,6 +30,7 @@
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -201,18 +202,26 @@
if (mAutofillProxies == null) {
mAutofillProxies = new SparseArray<>();
}
+
+ final ICancellationSignal transport = CancellationSignal.createTransport();
+ final CancellationSignal cancellationSignal = CancellationSignal.fromTransport(transport);
AutofillProxy proxy = mAutofillProxies.get(sessionId);
if (proxy == null) {
proxy = new AutofillProxy(sessionId, client, taskId, componentName, focusedId,
- focusedValue, requestTime, callback);
+ focusedValue, requestTime, callback, cancellationSignal);
mAutofillProxies.put(sessionId, proxy);
} else {
// TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
proxy.update(focusedId, focusedValue, callback);
}
- // TODO(b/123101711): set cancellation signal
- final CancellationSignal cancellationSignal = null;
+
+ try {
+ callback.onCancellable(transport);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+
onFillRequest(new FillRequest(proxy), cancellationSignal, new FillController(proxy),
new FillCallback(proxy));
}
@@ -329,18 +338,21 @@
@GuardedBy("mLock")
private FillWindow mFillWindow;
+ private CancellationSignal mCancellationSignal;
+
private AutofillProxy(int sessionId, @NonNull IBinder client, int taskId,
@NonNull ComponentName componentName, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime,
- @NonNull IFillCallback callback) {
+ @NonNull IFillCallback callback, @NonNull CancellationSignal cancellationSignal) {
mSessionId = sessionId;
mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
mCallback = callback;
this.taskId = taskId;
this.componentName = componentName;
- this.mFocusedId = focusedId;
- this.mFocusedValue = focusedValue;
- this.mFirstRequestTime = requestTime;
+ mFocusedId = focusedId;
+ mFocusedValue = focusedValue;
+ mFirstRequestTime = requestTime;
+ mCancellationSignal = cancellationSignal;
// TODO(b/123099468): linkToDeath
}
@@ -394,6 +406,12 @@
public void requestShowFillUi(int width, int height, Rect anchorBounds,
IAutofillWindowPresenter presenter) throws RemoteException {
+ if (mCancellationSignal.isCanceled()) {
+ if (VERBOSE) {
+ Log.v(TAG, "requestShowFillUi() not showing because request is cancelled");
+ }
+ return;
+ }
mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
presenter);
}
@@ -405,12 +423,16 @@
private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue,
@NonNull IFillCallback callback) {
synchronized (mLock) {
- // TODO(b/123099468): should we close the popupwindow if the focused id changed?
mFocusedId = focusedId;
mFocusedValue = focusedValue;
if (mCallback != null) {
- // TODO(b/123101711): we need to check whether the previous request was
- // completed or not, and if not, cancel it first.
+ try {
+ if (!mCallback.isCompleted()) {
+ mCallback.cancel();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "failed to check current pending request status", e);
+ }
Slog.d(TAG, "mCallback is updated.");
}
mCallback = callback;
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index 2b072664..88baa87 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -24,7 +24,8 @@
* @hide
*/
interface IFillCallback {
- // TODO(b/123101711): add cancellation (after we have CTS tests, so we can test it)
-// void onCancellable(in ICancellationSignal cancellation);
+ void onCancellable(in ICancellationSignal cancellation);
void onSuccess();
+ boolean isCompleted();
+ void cancel();
}
diff --git a/core/java/android/service/contentcapture/ActivityEvent.java b/core/java/android/service/contentcapture/ActivityEvent.java
index 7ac380d..fc781c2 100644
--- a/core/java/android/service/contentcapture/ActivityEvent.java
+++ b/core/java/android/service/contentcapture/ActivityEvent.java
@@ -47,10 +47,22 @@
*/
public static final int TYPE_ACTIVITY_PAUSED = Event.ACTIVITY_PAUSED;
+ /**
+ * The activity stopped.
+ */
+ public static final int TYPE_ACTIVITY_STOPPED = Event.ACTIVITY_STOPPED;
+
+ /**
+ * The activity was destroyed.
+ */
+ public static final int TYPE_ACTIVITY_DESTROYED = Event.ACTIVITY_DESTROYED;
+
/** @hide */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_ACTIVITY_RESUMED,
- TYPE_ACTIVITY_PAUSED
+ TYPE_ACTIVITY_PAUSED,
+ TYPE_ACTIVITY_STOPPED,
+ TYPE_ACTIVITY_DESTROYED
})
@Retention(RetentionPolicy.SOURCE)
public @interface ActivityEventType{}
@@ -75,7 +87,8 @@
/**
* Gets the event type.
*
- * @return either {@link #TYPE_ACTIVITY_RESUMED} or {@value #TYPE_ACTIVITY_PAUSED}.
+ * @return either {@link #TYPE_ACTIVITY_RESUMED}, {@value #TYPE_ACTIVITY_PAUSED},
+ * {@value #TYPE_ACTIVITY_STOPPED}, or {@value #TYPE_ACTIVITY_DESTROYED}.
*/
@ActivityEventType
public int getEventType() {
@@ -89,6 +102,10 @@
return "ACTIVITY_RESUMED";
case TYPE_ACTIVITY_PAUSED:
return "ACTIVITY_PAUSED";
+ case TYPE_ACTIVITY_STOPPED:
+ return "ACTIVITY_STOPPED";
+ case TYPE_ACTIVITY_DESTROYED:
+ return "ACTIVITY_DESTROYED";
default:
return "UKNOWN_TYPE: " + type;
}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 6f4114d..df11397 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -78,6 +78,21 @@
public static final String SERVICE_INTERFACE =
"android.service.contentcapture.ContentCaptureService";
+ /**
+ * Name under which a ContentCaptureService component publishes information about itself.
+ *
+ * <p>This meta-data should reference an XML resource containing a
+ * <code><{@link
+ * android.R.styleable#ContentCaptureService content-capture-service}></code> tag.
+ *
+ * <p>This is a a sample XML file configuring a ContentCaptureService:
+ * <pre> <content-capture-service
+ * android:settingsActivity="foo.bar.SettingsActivity"
+ * . . .
+ * /></pre>
+ */
+ public static final String SERVICE_META_DATA = "android.content_capture";
+
private Handler mHandler;
private IContentCaptureServiceCallback mCallback;
diff --git a/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
new file mode 100644
index 0000000..6ecd82f
--- /dev/null
+++ b/core/java/android/service/contentcapture/ContentCaptureServiceInfo.java
@@ -0,0 +1,171 @@
+/*
+ * 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 android.service.contentcapture;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * {@link ServiceInfo} and meta-data about an {@link ContentCaptureService}.
+ *
+ * @hide
+ */
+public final class ContentCaptureServiceInfo {
+
+ private static final String TAG = ContentCaptureServiceInfo.class.getSimpleName();
+ private static final String XML_TAG_SERVICE = "content-capture-service";
+
+ private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, boolean isTemp,
+ @UserIdInt int userId) throws PackageManager.NameNotFoundException {
+ int flags = PackageManager.GET_META_DATA;
+ if (!isTemp) {
+ flags |= PackageManager.MATCH_SYSTEM_ONLY;
+ }
+
+ ServiceInfo si = null;
+ try {
+ si = AppGlobals.getPackageManager().getServiceInfo(comp, flags, userId);
+ } catch (RemoteException e) {
+ }
+ if (si == null) {
+ throw new NameNotFoundException("Could not get serviceInfo for "
+ + (isTemp ? " (temp)" : "(default system)")
+ + " " + comp.flattenToShortString());
+ }
+ return si;
+ }
+
+ @NonNull
+ private final ServiceInfo mServiceInfo;
+
+ @Nullable
+ private final String mSettingsActivity;
+
+ public ContentCaptureServiceInfo(@NonNull Context context, @NonNull ComponentName comp,
+ boolean isTemporaryService, @UserIdInt int userId)
+ throws PackageManager.NameNotFoundException {
+ this(context, getServiceInfoOrThrow(comp, isTemporaryService, userId));
+ }
+
+ private ContentCaptureServiceInfo(@NonNull Context context, @NonNull ServiceInfo si) {
+ // Check for permissions.
+ if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) {
+ Slog.w(TAG, "ContentCaptureService from '" + si.packageName
+ + "' does not require permission "
+ + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
+ throw new SecurityException("Service does not require permission "
+ + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
+ }
+
+ mServiceInfo = si;
+
+ // Get the metadata, if declared.
+ final XmlResourceParser parser = si.loadXmlMetaData(context.getPackageManager(),
+ ContentCaptureService.SERVICE_META_DATA);
+ if (parser == null) {
+ mSettingsActivity = null;
+ return;
+ }
+
+ String settingsActivity = null;
+
+ try {
+ final Resources resources = context.getPackageManager().getResourcesForApplication(
+ si.applicationInfo);
+
+ int type = 0;
+ while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
+ type = parser.next();
+ }
+
+ if (XML_TAG_SERVICE.equals(parser.getName())) {
+ final AttributeSet allAttributes = Xml.asAttributeSet(parser);
+ TypedArray afsAttributes = null;
+ try {
+ afsAttributes = resources.obtainAttributes(allAttributes,
+ com.android.internal.R.styleable.ContentCaptureService);
+ settingsActivity = afsAttributes.getString(
+ R.styleable.ContentCaptureService_settingsActivity);
+ } finally {
+ if (afsAttributes != null) {
+ afsAttributes.recycle();
+ }
+ }
+ } else {
+ Log.e(TAG, "Meta-data does not start with content-capture-service tag");
+ }
+ } catch (PackageManager.NameNotFoundException | IOException | XmlPullParserException e) {
+ Log.e(TAG, "Error parsing auto fill service meta-data", e);
+ }
+
+ mSettingsActivity = settingsActivity;
+ }
+
+ public ServiceInfo getServiceInfo() {
+ return mServiceInfo;
+ }
+
+ @Nullable
+ public String getSettingsActivity() {
+ return mSettingsActivity;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder builder = new StringBuilder();
+ builder.append(getClass().getSimpleName());
+ builder.append("[").append(mServiceInfo);
+ builder.append(", settings:").append(mSettingsActivity);
+ return builder.toString();
+ }
+
+ /**
+ * Dumps it!
+ */
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ pw.print(prefix);
+ pw.print("Component: ");
+ pw.println(getServiceInfo().getComponentName());
+ pw.print(prefix);
+ pw.print("Settings: ");
+ pw.println(mSettingsActivity);
+ }
+}
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index a46d047..2288106 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -113,15 +113,27 @@
public static final String ACTION_PROVISION_EMBEDDED_SUBSCRIPTION =
"android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION";
- /** @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED */
+ /**
+ * @see android.telephony.euicc.EuiccManager#ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED. This is
+ * a protected intent that can only be sent by the system, and requires the
+ * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+ */
public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED =
"android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
- /** @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED */
+ /**
+ * @see android.telephony.euicc.EuiccManager#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED. This is
+ * a protected intent that can only be sent by the system, and requires the
+ * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+ */
public static final String ACTION_DELETE_SUBSCRIPTION_PRIVILEGED =
"android.service.euicc.action.DELETE_SUBSCRIPTION_PRIVILEGED";
- /** @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED */
+ /**
+ * @see android.telephony.euicc.EuiccManager#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED. This is
+ * a protected intent that can only be sent by the system, and requires the
+ * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+ */
public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED =
"android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
index 7a9d8a0..9add38e 100644
--- a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
+++ b/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
@@ -97,9 +97,10 @@
if (this.result == EuiccService.RESULT_OK) {
this.mProfiles = profiles;
} else {
- if (profiles != null) {
+ // For error case, profiles is either null or 0 size.
+ if (profiles != null && profiles.length > 0) {
throw new IllegalArgumentException(
- "Error result with non-null profiles: " + result);
+ "Error result with non-empty profiles: " + result);
}
this.mProfiles = null;
}
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 1cdb62f..8ba9a83 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -16,6 +16,7 @@
package android.service.notification;
import android.annotation.NonNull;
+import android.annotation.StringDef;
import android.annotation.SystemApi;
import android.app.Notification;
import android.os.Bundle;
@@ -23,6 +24,9 @@
import android.os.Parcelable;
import android.os.UserHandle;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Ranking updates from the Assistant.
*
@@ -43,6 +47,14 @@
private final Bundle mSignals;
private final int mUser;
+ /** @hide */
+ @StringDef (prefix = { "KEY_" }, value = {
+ KEY_CONTEXTUAL_ACTIONS, KEY_GROUP_KEY, KEY_IMPORTANCE, KEY_PEOPLE, KEY_SNOOZE_CRITERIA,
+ KEY_TEXT_REPLIES, KEY_USER_SENTIMENT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Keys {}
+
/**
* Data type: ArrayList of {@code String}, where each is a representation of a
* {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI}.
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 780b576..a1932b8 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.app.Notification;
import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
@@ -141,7 +142,6 @@
return onNotificationEnqueued(sbn);
}
-
/**
* Implement this method to learn when notifications are removed, how they were interacted with
* before removal, and why they were removed.
@@ -216,6 +216,15 @@
}
/**
+ * Implement this to know when a user has changed which features of
+ * their notifications the assistant can modify.
+ * <p> Query {@link NotificationManager#getAllowedAssistantCapabilities()} to see what
+ * {@link Adjustment adjustments} you are currently allowed to make.</p>
+ */
+ public void onCapabilitiesChanged() {
+ }
+
+ /**
* Updates a notification. N.B. this won’t cause
* an existing notification to alert, but might allow a future update to
* this notification to alert.
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index cc74e1a..8512a0b 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -292,9 +292,9 @@
return uid;
}
- /** The package that posted the notification.
- *<p>
- * Might be different from {@link #getPackageName()} if the app owning the notification has
+ /**
+ * The package that posted the notification.
+ * <p> Might be different from {@link #getPackageName()} if the app owning the notification has
* a {@link NotificationManager#setNotificationDelegate(String) notification delegate}.
*/
public @NonNull String getOpPkg() {
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 83f14d1..100774c 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -536,7 +536,7 @@
* or playing back a file. The value should be one of the STREAM_ constants
* defined in {@link AudioManager}.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_STREAM = "streamType";
@@ -546,7 +546,7 @@
* speaking text or playing back a file. The value should be set
* using {@link TextToSpeech#setAudioAttributes(AudioAttributes)}.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
* @hide
*/
@@ -557,7 +557,7 @@
* {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
* spoken, a file has been played back or a silence duration has elapsed.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
* @see TextToSpeech#synthesizeToFile(String, HashMap, String)
*/
@@ -568,7 +568,7 @@
* volume used when speaking text. Volume is specified as a float ranging from 0 to 1
* where 0 is silence, and 1 is the maximum volume (the default behavior).
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_VOLUME = "volume";
@@ -578,7 +578,7 @@
* Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
* 0 to center (the default behavior), and +1 to hard-right.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_PAN = "pan";
@@ -589,7 +589,7 @@
* as per {@link TextToSpeech#getFeatures(Locale)}, the engine must
* use network based synthesis.
*
- * @see TextToSpeech#speak(String, int, java.util.HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
* @see TextToSpeech#getFeatures(java.util.Locale)
*
@@ -607,7 +607,7 @@
* as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize
* text on-device (without making network requests).
*
- * @see TextToSpeech#speak(String, int, java.util.HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)
* @see TextToSpeech#getFeatures(java.util.Locale)
@@ -625,7 +625,7 @@
* output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect}
* objects with the synthesis (or earcon) output.
*
- * @see TextToSpeech#speak(String, int, HashMap)
+ * @see TextToSpeech#speak(CharSequence, int, Bundle, String)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_SESSION_ID = "sessionId";
@@ -881,7 +881,7 @@
/**
* Adds a mapping between a string of text and a sound resource in a
* package. After a call to this method, subsequent calls to
- * {@link #speak(String, int, HashMap)} will play the specified sound resource
+ * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
* if it is available, or synthesize the text it is missing.
*
* @param text
@@ -915,7 +915,7 @@
/**
* Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text
* and a sound resource in a package. After a call to this method, subsequent calls to
- * {@link #speak(String, int, HashMap)} will play the specified sound resource
+ * {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound resource
* if it is available, or synthesize the text it is missing.
*
* @param text
@@ -947,11 +947,10 @@
}
/**
- * Adds a mapping between a string of text and a sound file. Using this, it
- * is possible to add custom pronounciations for a string of text.
- * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
- * will play the specified sound resource if it is available, or synthesize the text it is
- * missing.
+ * Adds a mapping between a string of text and a sound file. Using this, it is possible to
+ * add custom pronounciations for a string of text. After a call to this method, subsequent
+ * calls to {@link #speak(CharSequence, int, Bundle, String)} will play the specified sound
+ * resource if it is available, or synthesize the text it is missing.
*
* @param text
* The string of text. Example: <code>"south_south_east"</code>
@@ -970,8 +969,8 @@
/**
* Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file.
- * Using this, it is possible to add custom pronounciations for a string of text.
- * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
+ * Using this, it is possible to add custom pronounciations for a string of text. After a call
+ * to this method, subsequent calls to {@link #speak(CharSequence, int, Bundle, String)}
* will play the specified sound resource if it is available, or synthesize the text it is
* missing.
*
diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java
index e43fd83..7cb9147 100644
--- a/core/java/android/text/style/LineBackgroundSpan.java
+++ b/core/java/android/text/style/LineBackgroundSpan.java
@@ -53,6 +53,15 @@
/**
* Default implementation of the {@link LineBackgroundSpan}, which changes the background
* color of the lines to which the span is attached.
+ * <p>
+ * For example, an <code>LineBackgroundSpan</code> can be used like this:
+ * <pre>
+ * String text = "This is a multiline text. LineBackgroundSpan is applied here. This is a multiline text.";
+ * SpannableString string = new SpannableString(text);
+ * string.setSpan(new LineBackgroundSpan.Standard(Color.YELLOW), 26, 61, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * </pre>
+ * <img src="{@docRoot}reference/android/images/text/style/linebackgroundspan.png" />
+ * <figcaption>Text with <code>LineBackgroundSpan</code></figcaption>
*/
class Standard implements LineBackgroundSpan, ParcelableSpan {
diff --git a/core/java/android/text/style/LineHeightSpan.java b/core/java/android/text/style/LineHeightSpan.java
index 7fb0f95..610cf2c 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -70,7 +70,15 @@
* Default implementation of the {@link LineHeightSpan}, which changes the line height of the
* attached paragraph.
* <p>
- * LineHeightSpan will change the line height of the entire paragraph, even though it
+ * For example, a paragraph with its line height equal to 100px can be set like this:
+ * <pre>
+ * SpannableString string = new SpannableString("This is a multiline paragraph. This is a multiline paragraph.");
+ * string.setSpan(new LineHeightSpan.Standard(100), 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * </pre>
+ * <img src="{@docRoot}reference/android/images/text/style/lineheightspan.png" />
+ * <figcaption>Text with line height set to 100 pixels.</figcaption>
+ * <p>
+ * Notice that LineHeightSpan will change the line height of the entire paragraph, even though it
* covers only part of the paragraph.
* </p>
*/
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c1504ae..de10ffb 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -51,7 +51,7 @@
DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
DEFAULT_FLAGS.put("settings_slice_injection", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
- DEFAULT_FLAGS.put("settings_mainline_module", "false");
+ DEFAULT_FLAGS.put("settings_mainline_module", "true");
DEFAULT_FLAGS.put("settings_dynamic_android", "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS
index 86ed122..98297fb 100644
--- a/core/java/android/util/OWNERS
+++ b/core/java/android/util/OWNERS
@@ -1,2 +1,3 @@
per-file FeatureFlagUtils.java = sbasi@google.com
per-file FeatureFlagUtils.java = zhfan@google.com
+per-file FeatureFlagUtils.java = asapperstein@google.com
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index b1f934a..597b34bf 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -73,4 +73,33 @@
* Hides the current input method if one is showing.
*/
void hideCurrentInputMethod();
+
+ /**
+ * Set a state for controller whether would like to cancel recents animations with deferred
+ * task screenshot presentation.
+ *
+ * When we cancel the recents animation due to a stack order change, we can't just cancel it
+ * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+ * leash. Instead we screenshot the previous task and replace the child of the leash with the
+ * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+ * transition animate smoothly without flickering.
+ *
+ * @param screenshot When set {@code true}, means recents animation will be canceled when the
+ * next app launch. System will take previous task's screenshot when the next
+ * app transition starting, and skip previous task's animation.
+ * Set {@code false} means will not take screenshot & skip animation
+ * for previous task.
+ *
+ * @see #cleanupScreenshot()
+ * @see IRecentsAnimationRunner#onCancelled
+ */
+ void setCancelWithDeferredScreenshot(boolean screenshot);
+
+ /**
+ * Clean up the screenshot of previous task which was created during recents animation that
+ * was cancelled by a stack order change.
+ *
+ * @see {@link IRecentsAnimationRunner#onAnimationCanceled}
+ */
+ void cleanupScreenshot();
}
diff --git a/core/java/android/view/IRecentsAnimationRunner.aidl b/core/java/android/view/IRecentsAnimationRunner.aidl
index 6e382f4..9c652a8 100644
--- a/core/java/android/view/IRecentsAnimationRunner.aidl
+++ b/core/java/android/view/IRecentsAnimationRunner.aidl
@@ -32,9 +32,17 @@
* Called when the system needs to cancel the current animation. This can be due to the
* wallpaper not drawing in time, or the handler not finishing the animation within a predefined
* amount of time.
+ *
+ * @param deferredWithScreenshot If set to {@code true}, the contents of the task will be
+ * replaced with a screenshot, such that the runner's leash is
+ * still active. As soon as the runner doesn't need the leash
+ * anymore, it can call
+ * {@link IRecentsAnimationController#cleanupScreenshot).
+ *
+ * @see {@link RecentsAnimationController#cleanupScreenshot}
*/
@UnsupportedAppUsage
- void onAnimationCanceled() = 1;
+ void onAnimationCanceled(boolean deferredWithScreenshot) = 1;
/**
* Called when the system is ready for the handler to start animating all the visible tasks.
diff --git a/core/java/android/view/ISystemGestureExclusionListener.aidl b/core/java/android/view/ISystemGestureExclusionListener.aidl
new file mode 100644
index 0000000..a032625
--- /dev/null
+++ b/core/java/android/view/ISystemGestureExclusionListener.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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 android.view;
+
+import android.graphics.Region;
+
+/**
+ * Listener for changes to the system gesture exclusion region
+ *
+ * {@hide}
+ */
+oneway interface ISystemGestureExclusionListener {
+ /**
+ * Called when the system gesture exclusion for the given display changed.
+ * @param displayId the display whose system gesture exclusion changed
+ * @param systemGestureExclusion a {@code Region} where the app would like priority over the
+ * system gestures, in display coordinates.
+ */
+ void onSystemGestureExclusionChanged(int displayId, in Region systemGestureExclusion);
+}
\ No newline at end of file
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e32c4e1..b91b93f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -40,6 +40,7 @@
import android.view.IPinnedStackListener;
import android.view.RemoteAnimationAdapter;
import android.view.IRotationWatcher;
+import android.view.ISystemGestureExclusionListener;
import android.view.IWallpaperVisibilityListener;
import android.view.IWindowSession;
import android.view.IWindowSessionCallback;
@@ -129,7 +130,7 @@
@UnsupportedAppUsage
boolean isKeyguardLocked();
@UnsupportedAppUsage
- boolean isKeyguardSecure();
+ boolean isKeyguardSecure(int userId);
void dismissKeyguard(IKeyguardDismissCallback callback, CharSequence message);
// Requires INTERACT_ACROSS_USERS_FULL permission
@@ -281,6 +282,18 @@
int displayId);
/**
+ * Registers a system gesture exclusion listener for a given display.
+ */
+ void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+ int displayId);
+
+ /**
+ * Unregisters a system gesture exclusion listener for a given display.
+ */
+ void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+ int displayId);
+
+ /**
* Used only for assist -- request a screenshot of the current application.
*/
boolean requestAssistScreenshot(IAssistDataReceiver receiver);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 1fcd432..87efb3f 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -32,6 +32,8 @@
import android.view.Surface;
import android.view.SurfaceControl;
+import java.util.List;
+
/**
* System private per-application interface to the window manager.
*
@@ -265,4 +267,10 @@
* that new state.
*/
void insetsModified(IWindow window, in InsetsState state);
+
+
+ /**
+ * Called when the system gesture exclusion has changed.
+ */
+ void reportSystemGestureExclusionChanged(IWindow window, in List<Rect> exclusionRects);
}
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index ec79eea..16a6412 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -18,9 +18,12 @@
import static android.view.Display.INVALID_DISPLAY;
+import android.annotation.Nullable;
import android.graphics.Region;
import android.os.IBinder;
+import java.lang.ref.WeakReference;
+
/**
* Functions as a handle for a window that can receive input.
* Enables the native input dispatcher to refer indirectly to the window manager's window state.
@@ -38,7 +41,7 @@
// The client window.
public final IWindow clientWindow;
- // The token assosciated with the window.
+ // The token associated with the window.
public IBinder token;
// The window name.
@@ -98,6 +101,23 @@
// transports the touch of this window to the display indicated by portalToDisplayId.
public int portalToDisplayId = INVALID_DISPLAY;
+ /**
+ * Crops the touchable region to the bounds of the surface provided.
+ *
+ * This can be used in cases where the window is not
+ * {@link android.view.WindowManager#FLAG_NOT_TOUCH_MODAL} but should be constrained to the
+ * bounds of a parent window. That is the window should receive touch events outside its
+ * window but be limited to its stack bounds, such as in the case of split screen.
+ */
+ public WeakReference<IBinder> touchableRegionCropHandle = new WeakReference<>(null);
+
+ /**
+ * Replace {@link touchableRegion} with the bounds of {@link touchableRegionCropHandle}. If
+ * the handle is {@code null}, the bounds of the surface associated with this window is used
+ * as the touchable region.
+ */
+ public boolean replaceTouchableRegionWithCrop;
+
private native void nativeDispose();
public InputWindowHandle(InputApplicationHandle inputApplicationHandle,
@@ -127,4 +147,25 @@
super.finalize();
}
}
+
+ /**
+ * Set the window touchable region to the bounds of {@link touchableRegionBounds} ignoring any
+ * touchable region provided.
+ *
+ * @param bounds surface to set the touchable region to. Set to {@code null} to set the bounds
+ * to the current surface.
+ */
+ public void replaceTouchableRegionWithCrop(@Nullable SurfaceControl bounds) {
+ setTouchableRegionCrop(bounds);
+ replaceTouchableRegionWithCrop = true;
+ }
+
+ /**
+ * Crop the window touchable region to the bounds of the surface provided.
+ */
+ public void setTouchableRegionCrop(@Nullable SurfaceControl bounds) {
+ if (bounds != null) {
+ touchableRegionCropHandle = new WeakReference<>(bounds.getHandle());
+ }
+ }
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 2d7e179..6129b38 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -145,7 +145,14 @@
// TODO: set system gesture insets based on actual system gesture area.
typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
- typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
+ typeInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] =
+ Insets.of(legacyContentInsets);
+ typeInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyContentInsets);
+
+ typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyStableInsets);
+ typeMaxInsetsMap[Type.indexOf(Type.mandatorySystemGestures())] =
+ Insets.of(legacyStableInsets);
+ typeMaxInsetsMap[Type.indexOf(Type.tappableElement())] = Insets.of(legacyStableInsets);
}
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources.get(type);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b857f1e..75067d3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -125,8 +125,8 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
-import android.view.inspector.InspectableProperty.FlagMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
+import android.view.inspector.InspectableProperty.FlagEntry;
import android.widget.Checkable;
import android.widget.FrameLayout;
import android.widget.ScrollBarDrawable;
@@ -6897,13 +6897,13 @@
* @return a bitmask representing the enabled scroll indicators
*/
@InspectableProperty(flagMapping = {
- @FlagMap(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
- @FlagMap(target = SCROLL_INDICATOR_TOP, name = "top"),
- @FlagMap(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
- @FlagMap(target = SCROLL_INDICATOR_LEFT, name = "left"),
- @FlagMap(target = SCROLL_INDICATOR_RIGHT, name = "right"),
- @FlagMap(target = SCROLL_INDICATOR_START, name = "start"),
- @FlagMap(target = SCROLL_INDICATOR_END, name = "end")
+ @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"),
+ @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"),
+ @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"),
+ @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"),
+ @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"),
+ @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"),
+ @FlagEntry(target = SCROLL_INDICATOR_END, name = "end")
})
@ScrollIndicators
public int getScrollIndicators() {
@@ -9032,12 +9032,12 @@
@ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
to = "noExcludeDescendants")})
@InspectableProperty(enumMapping = {
- @EnumMap(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
- @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
- @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
- @EnumMap(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
+ @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"),
+ @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"),
+ @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"),
+ @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
name = "yesExcludeDescendants"),
- @EnumMap(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
+ @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS,
name = "noExcludeDescendants"),
})
public @AutofillImportance int getImportantForAutofill() {
@@ -9225,12 +9225,12 @@
@ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
to = "noExcludeDescendants")})
@InspectableProperty(enumMapping = {
- @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
- @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
- @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
- @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
+ @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"),
+ @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"),
+ @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"),
+ @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS,
name = "yesExcludeDescendants"),
- @EnumMap(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
+ @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS,
name = "noExcludeDescendants"),
})
public @ContentCaptureImportance int getImportantForContentCapture() {
@@ -10534,9 +10534,9 @@
@Deprecated
@DrawingCacheQuality
@InspectableProperty(enumMapping = {
- @EnumMap(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
- @EnumMap(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
- @EnumMap(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
+ @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"),
+ @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"),
+ @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto")
})
public int getDrawingCacheQuality() {
return mViewFlags & DRAWING_CACHE_QUALITY_MASK;
@@ -11090,11 +11090,10 @@
* <p>Computes the coordinates of this view in its surface. The argument
* must be an array of two integers. After the method returns, the array
* contains the x and y location in that order.</p>
- * @hide
+ *
* @param location an array of two integers in which to hold the coordinates
*/
- @UnsupportedAppUsage
- public void getLocationInSurface(@Size(2) int[] location) {
+ public void getLocationInSurface(@NonNull @Size(2) int[] location) {
getLocationInWindow(location);
if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) {
location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left;
@@ -11276,9 +11275,9 @@
@ViewDebug.IntToString(from = GONE, to = "GONE")
})
@InspectableProperty(enumMapping = {
- @EnumMap(value = VISIBLE, name = "visible"),
- @EnumMap(value = INVISIBLE, name = "invisible"),
- @EnumMap(value = GONE, name = "gone")
+ @EnumEntry(value = VISIBLE, name = "visible"),
+ @EnumEntry(value = INVISIBLE, name = "invisible"),
+ @EnumEntry(value = GONE, name = "gone")
})
@Visibility
public int getVisibility() {
@@ -11527,10 +11526,10 @@
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE")
})
@InspectableProperty(hasAttributeId = false, enumMapping = {
- @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
- @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
- @EnumMap(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
- @EnumMap(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
+ @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+ @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"),
+ @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"),
+ @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale")
})
@LayoutDir
public int getRawLayoutDirection() {
@@ -11586,8 +11585,8 @@
@ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL")
})
@InspectableProperty(enumMapping = {
- @EnumMap(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
- @EnumMap(value = LAYOUT_DIRECTION_RTL, name = "rtl")
+ @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"),
+ @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl")
})
@ResolvedLayoutDir
public int getLayoutDirection() {
@@ -12072,9 +12071,9 @@
@ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO")
}, category = "focus")
@InspectableProperty(enumMapping = {
- @EnumMap(value = NOT_FOCUSABLE, name = "false"),
- @EnumMap(value = FOCUSABLE, name = "true"),
- @EnumMap(value = FOCUSABLE_AUTO, name = "auto")
+ @EnumEntry(value = NOT_FOCUSABLE, name = "false"),
+ @EnumEntry(value = FOCUSABLE, name = "true"),
+ @EnumEntry(value = FOCUSABLE_AUTO, name = "auto")
})
@Focusable
public int getFocusable() {
@@ -12957,10 +12956,10 @@
to = "noHideDescendants")
})
@InspectableProperty(enumMapping = {
- @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
- @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
- @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
- @EnumMap(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+ @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"),
+ @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"),
+ @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"),
+ @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
name = "noHideDescendants"),
})
public int getImportantForAccessibility() {
@@ -13016,9 +13015,9 @@
* @see #setAccessibilityLiveRegion(int)
*/
@InspectableProperty(enumMapping = {
- @EnumMap(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
- @EnumMap(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
- @EnumMap(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
+ @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"),
+ @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"),
+ @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive")
})
public int getAccessibilityLiveRegion() {
return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK)
@@ -18625,9 +18624,9 @@
* @hide
*/
@InspectableProperty(name = "requiresFadingEdge", flagMapping = {
- @FlagMap(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
- @FlagMap(target = FADING_EDGE_VERTICAL, name = "vertical"),
- @FlagMap(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
+ @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"),
+ @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"),
+ @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal")
})
public int getFadingEdge() {
return mViewFlags & FADING_EDGE_MASK;
@@ -18922,10 +18921,10 @@
@ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET")
})
@InspectableProperty(name = "scrollbarStyle", enumMapping = {
- @EnumMap(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
- @EnumMap(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
- @EnumMap(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
- @EnumMap(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
+ @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"),
+ @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"),
+ @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"),
+ @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset")
})
@ScrollBarStyle
public int getScrollBarStyle() {
@@ -20478,9 +20477,9 @@
* @see #LAYER_TYPE_HARDWARE
*/
@InspectableProperty(enumMapping = {
- @EnumMap(value = LAYER_TYPE_NONE, name = "none"),
- @EnumMap(value = LAYER_TYPE_SOFTWARE, name = "software"),
- @EnumMap(value = LAYER_TYPE_HARDWARE, name = "hardware")
+ @EnumEntry(value = LAYER_TYPE_NONE, name = "none"),
+ @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"),
+ @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware")
})
@LayerType
public int getLayerType() {
@@ -26160,9 +26159,9 @@
* @return This view's over-scroll mode.
*/
@InspectableProperty(enumMapping = {
- @EnumMap(value = OVER_SCROLL_ALWAYS, name = "always"),
- @EnumMap(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
- @EnumMap(value = OVER_SCROLL_NEVER, name = "never")
+ @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"),
+ @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"),
+ @EnumEntry(value = OVER_SCROLL_NEVER, name = "never")
})
public int getOverScrollMode() {
return mOverScrollMode;
@@ -26553,14 +26552,14 @@
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
})
@InspectableProperty(hasAttributeId = false, enumMapping = {
- @EnumMap(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
- @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
- @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
- @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
- @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
- @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
- @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
- @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+ @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"),
+ @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+ @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+ @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"),
+ @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"),
+ @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+ @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+ @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
})
@UnsupportedAppUsage
public int getRawTextDirection() {
@@ -26630,13 +26629,13 @@
@ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
})
@InspectableProperty(hasAttributeId = false, enumMapping = {
- @EnumMap(value = TEXT_DIRECTION_LOCALE, name = "locale"),
- @EnumMap(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
- @EnumMap(value = TEXT_DIRECTION_LTR, name = "ltr"),
- @EnumMap(value = TEXT_DIRECTION_RTL, name = "rtl"),
- @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
- @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
- @EnumMap(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
+ @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"),
+ @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"),
+ @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"),
+ @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"),
+ @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"),
+ @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"),
+ @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"),
})
public int getTextDirection() {
return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
@@ -26810,13 +26809,13 @@
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
})
@InspectableProperty(hasAttributeId = false, enumMapping = {
- @EnumMap(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
- @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
- @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
- @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
- @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
- @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
- @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+ @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"),
+ @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+ @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+ @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+ @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+ @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+ @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
})
@TextAlignment
@UnsupportedAppUsage
@@ -26885,12 +26884,12 @@
@ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END")
})
@InspectableProperty(enumMapping = {
- @EnumMap(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
- @EnumMap(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
- @EnumMap(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
- @EnumMap(value = TEXT_ALIGNMENT_CENTER, name = "center"),
- @EnumMap(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
- @EnumMap(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
+ @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"),
+ @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"),
+ @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"),
+ @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"),
+ @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"),
+ @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd")
})
@TextAlignment
public int getTextAlignment() {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4964ee1..a4d80dc 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -61,7 +61,7 @@
import android.view.animation.Transformation;
import android.view.autofill.Helper;
import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
import com.android.internal.R;
@@ -778,9 +778,9 @@
@ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
})
@InspectableProperty(enumMapping = {
- @EnumMap(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
- @EnumMap(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
- @EnumMap(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
+ @EnumEntry(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
+ @EnumEntry(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
+ @EnumEntry(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
})
public int getDescendantFocusability() {
return mGroupFlags & FLAG_MASK_FOCUSABILITY;
@@ -6574,10 +6574,10 @@
@ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
})
@InspectableProperty(enumMapping = {
- @EnumMap(value = PERSISTENT_NO_CACHE, name = "none"),
- @EnumMap(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
- @EnumMap(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
- @EnumMap(value = PERSISTENT_ALL_CACHES, name = "all"),
+ @EnumEntry(value = PERSISTENT_NO_CACHE, name = "none"),
+ @EnumEntry(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
+ @EnumEntry(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
+ @EnumEntry(value = PERSISTENT_ALL_CACHES, name = "all"),
})
public int getPersistentDrawingCache() {
return mPersistentDrawingCache;
@@ -6657,8 +6657,8 @@
* @see #setLayoutMode(int)
*/
@InspectableProperty(enumMapping = {
- @EnumMap(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
- @EnumMap(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
+ @EnumEntry(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
+ @EnumEntry(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
})
public int getLayoutMode() {
if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
@@ -7849,8 +7849,8 @@
@ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
})
@InspectableProperty(name = "layout_width", enumMapping = {
- @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
- @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
+ @EnumEntry(name = "match_parent", value = MATCH_PARENT),
+ @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
})
public int width;
@@ -7864,8 +7864,8 @@
@ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
})
@InspectableProperty(name = "layout_height", enumMapping = {
- @InspectableProperty.EnumMap(name = "match_parent", value = MATCH_PARENT),
- @InspectableProperty.EnumMap(name = "wrap_content", value = WRAP_CONTENT)
+ @EnumEntry(name = "match_parent", value = MATCH_PARENT),
+ @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
})
public int height;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9222bd6..6d04cd31 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1213,15 +1213,12 @@
boolean useAutoDark = getNightMode() == Configuration.UI_MODE_NIGHT_YES;
- // Allow debug.hwui.force_dark to override the target SDK check
- if (useAutoDark && !SystemProperties.getBoolean("debug.hwui.force_dark", false)) {
- useAutoDark = mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q;
- }
-
if (useAutoDark) {
+ boolean forceDarkAllowedDefault =
+ SystemProperties.getBoolean("debug.hwui.force_dark", false);
TypedArray a = mContext.obtainStyledAttributes(R.styleable.Theme);
useAutoDark = a.getBoolean(R.styleable.Theme_isLightTheme, true)
- && a.getBoolean(R.styleable.Theme_forceDarkAllowed, true);
+ && a.getBoolean(R.styleable.Theme_forceDarkAllowed, forceDarkAllowedDefault);
a.recycle();
}
@@ -3990,7 +3987,11 @@
void systemGestureExclusionChanged() {
final List<Rect> rectsForWindowManager = mGestureExclusionTracker.computeChangedRects();
if (rectsForWindowManager != null) {
- // TODO Send to WM
+ try {
+ mWindowSession.reportSystemGestureExclusionChanged(mWindow, rectsForWindowManager);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
mAttachInfo.mTreeObserver
.dispatchOnSystemGestureExclusionRectsChanged(rectsForWindowManager);
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index f1a992c..aac0e34 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -20,14 +20,18 @@
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.LAST;
+import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIDE_BARS;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
+import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
import static android.view.WindowInsets.Type.TOP_BAR;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.compatSystemInsets;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.mandatorySystemGestures;
import static android.view.WindowInsets.Type.systemGestures;
+import static android.view.WindowInsets.Type.tappableElement;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -223,6 +227,8 @@
assignCompatInsets(typeInsetMap, insets);
// TODO: set system gesture insets based on actual system gesture area.
typeInsetMap[indexOf(systemGestures())] = Insets.of(insets);
+ typeInsetMap[indexOf(mandatorySystemGestures())] = Insets.of(insets);
+ typeInsetMap[indexOf(tappableElement())] = Insets.of(insets);
return typeInsetMap;
}
@@ -639,15 +645,22 @@
* priority and may consume some or all touch input, e.g. due to the a system bar
* occupying it, or it being reserved for touch-only gestures.
*
+ * <p>An app can declare priority over system gestures with
+ * {@link View#setSystemGestureExclusionRects} outside of the
+ * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
+ *
* <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
- * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
+ * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
*
* <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
* even when the system gestures are inactive due to
* {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
* {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
*
- * <p>This inset does not affect the result of {@link #isConsumed()} and cannot be consumed.
+ * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+ * system window insets} by {@link #consumeSystemWindowInsets()}.
+ *
+ * @see #getMandatorySystemGestureInsets
*/
@NonNull
public Insets getSystemGestureInsets() {
@@ -655,6 +668,60 @@
}
/**
+ * Returns the mandatory system gesture insets.
+ *
+ * <p>The mandatory system gesture insets represent the area of a window where mandatory system
+ * gestures have priority and may consume some or all touch input, e.g. due to the a system bar
+ * occupying it, or it being reserved for touch-only gestures.
+ *
+ * <p>In contrast to {@link #getSystemGestureInsets regular system gestures}, <b>mandatory</b>
+ * system gestures cannot be overriden by {@link View#setSystemGestureExclusionRects}.
+ *
+ * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
+ * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
+ *
+ * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
+ * even when the system gestures are inactive due to
+ * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
+ * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ *
+ * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+ * system window insets} by {@link #consumeSystemWindowInsets()}.
+ *
+ * @see #getSystemGestureInsets
+ */
+ @NonNull
+ public Insets getMandatorySystemGestureInsets() {
+ return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES);
+ }
+
+ /**
+ * Returns the tappable element insets.
+ *
+ * <p>The tappable element insets represent how much tappable elements <b>must at least</b> be
+ * inset to remain both tappable and visually unobstructed by persistent system windows.
+ *
+ * <p>This may be smaller than {@link #getSystemWindowInsets()} if the system window is
+ * largely transparent and lets through simple taps (but not necessarily more complex gestures).
+ *
+ * <p>Note that generally, tappable elements <strong>should</strong> be aligned with the
+ * {@link #getSystemWindowInsets() system window insets} instead to avoid overlapping with the
+ * system bars.
+ *
+ * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
+ * even when the area covered by the inset would be tappable due to
+ * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
+ * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
+ *
+ * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
+ * system window insets} by {@link #consumeSystemWindowInsets()}.
+ */
+ @NonNull
+ public Insets getTappableElementInsets() {
+ return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
+ }
+
+ /**
* Returns a copy of this WindowInsets with the stable insets fully consumed.
*
* @return A modified copy of this WindowInsets
@@ -895,6 +962,41 @@
}
/**
+ * Sets mandatory system gesture insets in pixels.
+ *
+ * <p>The mandatory system gesture insets represent the area of a window where mandatory
+ * system gestures have priority and may consume some or all touch input, e.g. due to the a
+ * system bar occupying it, or it being reserved for touch-only gestures.
+ *
+ * <p>In contrast to {@link #setSystemGestureInsets regular system gestures},
+ * <b>mandatory</b> system gestures cannot be overriden by
+ * {@link View#setSystemGestureExclusionRects}.
+ *
+ * @see #getMandatorySystemGestureInsets()
+ * @return itself
+ */
+ @NonNull
+ public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) {
+ WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets);
+ return this;
+ }
+
+ /**
+ * Sets tappable element insets in pixels.
+ *
+ * <p>The tappable element insets represent how much tappable elements <b>must at least</b>
+ * be inset to remain both tappable and visually unobstructed by persistent system windows.
+ *
+ * @see #getTappableElementInsets()
+ * @return itself
+ */
+ @NonNull
+ public Builder setTappableElementInsets(@NonNull Insets insets) {
+ WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
+ return this;
+ }
+
+ /**
* Sets the insets of a specific window type in pixels.
*
* <p>The insets represents the area of a a window that is partially or fully obscured by
@@ -1041,16 +1143,18 @@
*/
public static final class Type {
- static final int FIRST = 0x1;
+ static final int FIRST = 1 << 0;
static final int TOP_BAR = FIRST;
- static final int IME = 0x2;
- static final int SIDE_BARS = 0x4;
+ static final int IME = 1 << 1;
+ static final int SIDE_BARS = 1 << 2;
- static final int SYSTEM_GESTURES = 0x8;
+ static final int SYSTEM_GESTURES = 1 << 3;
+ static final int MANDATORY_SYSTEM_GESTURES = 1 << 4;
+ static final int TAPPABLE_ELEMENT = 1 << 5;
- static final int LAST = 0x10;
- static final int SIZE = 5;
+ static final int LAST = 1 << 6;
+ static final int SIZE = 7;
static final int WINDOW_DECOR = LAST;
static int indexOf(@InsetType int type) {
@@ -1063,8 +1167,12 @@
return 2;
case SYSTEM_GESTURES:
return 3;
- case WINDOW_DECOR:
+ case MANDATORY_SYSTEM_GESTURES:
return 4;
+ case TAPPABLE_ELEMENT:
+ return 5;
+ case WINDOW_DECOR:
+ return 6;
default:
throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
+ " type=" + type);
@@ -1076,7 +1184,8 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES })
+ @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES,
+ MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
public @interface InsetType {
}
@@ -1131,6 +1240,20 @@
}
/**
+ * @see #getMandatorySystemGestureInsets
+ */
+ public static @InsetType int mandatorySystemGestures() {
+ return MANDATORY_SYSTEM_GESTURES;
+ }
+
+ /**
+ * @see #getTappableElementInsets
+ */
+ public static @InsetType int tappableElement() {
+ return TAPPABLE_ELEMENT;
+ }
+
+ /**
* @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
* not {@link #ime()}.
*/
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 13efeaf..8cb04cb 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -20,6 +20,7 @@
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
+import static android.view.autofill.Helper.toList;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.annotation.IntDef;
@@ -227,6 +228,9 @@
/** @hide */ public static final int FLAG_ADD_CLIENT_ENABLED = 0x1;
/** @hide */ public static final int FLAG_ADD_CLIENT_DEBUG = 0x2;
/** @hide */ public static final int FLAG_ADD_CLIENT_VERBOSE = 0x4;
+
+ /** @hide */ public static final int FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY = 0x1;
+
/** @hide */
public static final int DEFAULT_LOGGING_LEVEL = Build.IS_DEBUGGABLE
? AutofillManager.FLAG_ADD_CLIENT_DEBUG
@@ -306,8 +310,8 @@
/**
* Same as {@link #STATE_UNKNOWN}, but used on
- * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
- * the URL bar changed on client mode
+ * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished
+ * because the URL bar changed on client mode
*
* @hide
*/
@@ -315,8 +319,8 @@
/**
* Same as {@link #STATE_UNKNOWN}, but used on
- * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
- * the service failed to fullfil a request.
+ * {@link AutofillManagerClient#setSessionFinished(int, List)} when the session was finished
+ * because the service failed to fullfil a request.
*
* @hide
*/
@@ -435,7 +439,7 @@
* There is currently no session running.
* {@hide}
*/
- public static final int NO_SESSION = Integer.MIN_VALUE;
+ public static final int NO_SESSION = Integer.MAX_VALUE;
private final IAutoFillManager mService;
@@ -512,6 +516,10 @@
@Nullable
private final AutofillOptions mOptions;
+ /** When set, session is only used for augmented autofill requests. */
+ @GuardedBy("mLock")
+ private boolean mForAugmentedAutofillOnly;
+
/** @hide */
public interface AutofillClient {
/**
@@ -939,9 +947,8 @@
ensureServiceClientAddedIfNeededLocked();
if (!mEnabled) {
- if (sVerbose) {
- Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
- }
+ if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled");
+
if (mCallback != null) {
callback = mCallback;
}
@@ -1024,6 +1031,12 @@
private void notifyViewVisibilityChangedInternal(@NonNull View view, int virtualId,
boolean isVisible, boolean virtual) {
synchronized (mLock) {
+ if (mForAugmentedAutofillOnly) {
+ if (sVerbose) {
+ Log.v(TAG, "notifyViewVisibilityChanged(): ignoring on augmented only mode");
+ }
+ return;
+ }
if (mEnabled && isActiveLocked()) {
final AutofillId id = virtual ? getAutofillId(view, virtualId)
: view.getAutofillId();
@@ -1167,6 +1180,10 @@
AutofillValue value = null;
synchronized (mLock) {
+ if (mForAugmentedAutofillOnly) {
+ if (sVerbose) Log.v(TAG, "notifyValueChanged(): ignoring on augmented only mode");
+ return;
+ }
// If the session is gone some fields might still be highlighted, hence we have to
// remove the isAutofilled property even if no sessions are active.
if (mLastAutofilledData == null) {
@@ -1220,6 +1237,10 @@
return;
}
synchronized (mLock) {
+ if (mForAugmentedAutofillOnly) {
+ if (sVerbose) Log.v(TAG, "notifyValueChanged(): ignoring on augmented only mode");
+ return;
+ }
if (!mEnabled || !isActiveLocked()) {
if (sVerbose) {
Log.v(TAG, "notifyValueChanged(" + view.getAutofillId() + ":" + virtualId
@@ -1675,14 +1696,20 @@
if (client == null) return; // NOTE: getClient() already logged it..
final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+ final ComponentName componentName = client.autofillClientGetComponentName();
mService.startSession(client.autofillClientGetActivityToken(),
mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
- mCallback != null, flags, client.autofillClientGetComponentName(),
+ mCallback != null, flags, componentName,
isCompatibilityModeEnabledLocked(), receiver);
mSessionId = receiver.getIntResult();
if (mSessionId != NO_SESSION) {
mState = STATE_ACTIVE;
}
+ final int extraFlags = receiver.getOptionalExtraIntResult(0);
+ if ((extraFlags & FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) != 0) {
+ if (sDebug) Log.d(TAG, "startSession(" + componentName + "): for augmented only");
+ mForAugmentedAutofillOnly = true;
+ }
client.autofillClientResetableStateAvailable();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1872,10 +1899,6 @@
}
}
- private <T> ArrayList<T> toList(@Nullable Set<T> set) {
- return set == null ? null : new ArrayList<T>(set);
- }
-
/**
* Notifies that a non-autofillable view was entered because the activity is whitelisted for
* augmented autofill.
@@ -2403,6 +2426,9 @@
pw.print(pfx); pw.print("entered ids for augmented autofill: ");
pw.println(mEnteredForAugmentedAutofillIds);
}
+ if (mForAugmentedAutofillOnly) {
+ pw.print(pfx); pw.println("For Augmented Autofill Only");
+ }
pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
if (mOptions != null) {
@@ -3149,6 +3175,10 @@
if (afm == null) return null;
final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id);
+ if (view == null) {
+ Log.w(TAG, "getViewCoordinates(" + id + "): could not find view");
+ return null;
+ }
final Rect windowVisibleDisplayFrame = new Rect();
view.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
final int[] location = new int[2];
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index 48d0dbb..2f12bb2 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -19,7 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Set;
/** @hide */
public final class Helper {
@@ -62,7 +64,8 @@
}
/**
- * Convers a collaction of {@link AutofillId AutofillIds} to an array.
+ * Converts a collaction of {@link AutofillId AutofillIds} to an array.
+ *
* @param collection The collection.
* @return The array.
*/
@@ -75,6 +78,14 @@
return array;
}
+ /**
+ * Converts a Set to a List.
+ */
+ @Nullable
+ public static <T> ArrayList<T> toList(@Nullable Set<T> set) {
+ return set == null ? null : new ArrayList<T>(set);
+ }
+
private Helper() {
throw new UnsupportedOperationException("contains static members only");
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 019ebff..5a27e94 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -161,7 +161,7 @@
/**
* Gets the context id.
*/
- @NonNull
+ @Nullable
public LocusId getLocusId() {
return mId;
}
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 4129e52..6d41b28 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -153,6 +153,8 @@
public static final int FLUSH_REASON_SESSION_FINISHED = 4;
/** @hide */
public static final int FLUSH_REASON_IDLE_TIMEOUT = 5;
+ /** @hide */
+ public static final int FLUSH_REASON_TEXT_CHANGE_TIMEOUT = 6;
/** @hide */
@IntDef(prefix = { "FLUSH_REASON_" }, value = {
@@ -160,7 +162,8 @@
FLUSH_REASON_VIEW_ROOT_ENTERED,
FLUSH_REASON_SESSION_STARTED,
FLUSH_REASON_SESSION_FINISHED,
- FLUSH_REASON_IDLE_TIMEOUT
+ FLUSH_REASON_IDLE_TIMEOUT,
+ FLUSH_REASON_TEXT_CHANGE_TIMEOUT
})
@Retention(RetentionPolicy.SOURCE)
public @interface FlushReason{}
@@ -525,6 +528,8 @@
return "FINISHED";
case FLUSH_REASON_IDLE_TIMEOUT:
return "IDLE";
+ case FLUSH_REASON_TEXT_CHANGE_TIMEOUT:
+ return "TEXT_CHANGE";
default:
return "UNKOWN-" + reason;
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index f9fd0c6..666af59 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -125,6 +125,11 @@
// Used just for debugging purposes (on dump)
private long mNextFlush;
+ /**
+ * Whether the next buffer flush is queued by a text changed event.
+ */
+ private boolean mNextFlushForTextChanged = false;
+
@Nullable
private final LocalLog mFlushHistory;
@@ -331,7 +336,21 @@
final boolean bufferEvent = numberEvents < maxBufferSize;
if (bufferEvent && !forceFlush) {
- scheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
+ final int flushReason;
+ if (eventType == TYPE_VIEW_TEXT_CHANGED) {
+ mNextFlushForTextChanged = true;
+ flushReason = FLUSH_REASON_TEXT_CHANGE_TIMEOUT;
+ } else {
+ if (mNextFlushForTextChanged) {
+ if (sVerbose) {
+ Log.i(TAG, "Not scheduling flush because next flush is for text changed");
+ }
+ return;
+ }
+
+ flushReason = FLUSH_REASON_IDLE_TIMEOUT;
+ }
+ scheduleFlush(flushReason, /* checkExisting= */ true);
return;
}
@@ -392,14 +411,25 @@
// "Renew" the flush message by removing the previous one
mHandler.removeMessages(MSG_FLUSH);
}
- final int idleFlushingFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
- mNextFlush = System.currentTimeMillis() + idleFlushingFrequencyMs;
+
+ final int flushFrequencyMs;
+ if (reason == FLUSH_REASON_IDLE_TIMEOUT) {
+ flushFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
+ } else if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
+ flushFrequencyMs = mManager.mOptions.textChangeFlushingFrequencyMs;
+ } else {
+ Log.e(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): not called with a "
+ + "timeout reason.");
+ return;
+ }
+
+ mNextFlush = System.currentTimeMillis() + flushFrequencyMs;
if (sVerbose) {
Log.v(TAG, "handleScheduleFlush(): scheduled to flush in "
- + idleFlushingFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
+ + flushFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
}
// Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage()
- mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, idleFlushingFrequencyMs);
+ mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, flushFrequencyMs);
}
@UiThread
@@ -448,6 +478,10 @@
try {
mHandler.removeMessages(MSG_FLUSH);
+ if (reason == FLUSH_REASON_TEXT_CHANGE_TIMEOUT) {
+ mNextFlushForTextChanged = false;
+ }
+
final ParceledListSlice<ContentCaptureEvent> events = clearEvents();
mDirectServiceInterface.sendEvents(events);
} catch (RemoteException e) {
@@ -625,8 +659,14 @@
pw.println();
}
}
+ pw.print(prefix); pw.print("mNextFlushForTextChanged: ");
+ pw.println(mNextFlushForTextChanged);
pw.print(prefix); pw.print("flush frequency: ");
- pw.println(mManager.mOptions.idleFlushingFrequencyMs);
+ if (mNextFlushForTextChanged) {
+ pw.println(mManager.mOptions.textChangeFlushingFrequencyMs);
+ } else {
+ pw.println(mManager.mOptions.idleFlushingFrequencyMs);
+ }
pw.print(prefix); pw.print("next flush: ");
TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
diff --git a/core/java/android/view/inspector/InspectableNodeName.java b/core/java/android/view/inspector/InspectableNodeName.java
deleted file mode 100644
index 7b9a507..0000000
--- a/core/java/android/view/inspector/InspectableNodeName.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.
- */
-
-package android.view.inspector;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.TestApi;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * Marks the node name to display to a developer in the inspection tree.
- *
- * This annotation is optional to marking a class as inspectable. If it is omitted, the node name
- * will be inferred using the semantics of {@link Class#getSimpleName()}. The fully qualified class
- * name is always available in the tree, this is for display purposes only. If a class is inflated
- * from XML and the tag it inflates from does not match its simple name, this annotation should be
- * used to inform the inspector to display the XML tag name in the inspection tree view.
- *
- * This annotation does not inherit. If a class extends an annotated parent class, but does not
- * annotate itself, its node name will be inferred from its Java name.
- *
- * @see InspectionCompanion#getNodeName()
- * @hide
- */
-@Target({TYPE})
-@Retention(SOURCE)
-@TestApi
-public @interface InspectableNodeName {
- /**
- * The display name for nodes of this type.
- *
- * @return The name for nodes of this type
- */
- String value();
-}
diff --git a/core/java/android/view/inspector/InspectableProperty.java b/core/java/android/view/inspector/InspectableProperty.java
index 97ede86..03f1ec5 100644
--- a/core/java/android/view/inspector/InspectableProperty.java
+++ b/core/java/android/view/inspector/InspectableProperty.java
@@ -87,21 +87,21 @@
*
* Note that {@link #enumMapping()} cannot be used simultaneously with {@link #flagMapping()}.
*
- * @return An array of {@link EnumMap}, empty if not applicable
+ * @return An array of {@link EnumEntry}, empty if not applicable
* @see android.annotation.IntDef
*/
- EnumMap[] enumMapping() default {};
+ EnumEntry[] enumMapping() default {};
/**
* For flags packed into primitive {int} properties, model the string names of the flags.
*
* Note that {@link #flagMapping()} cannot be used simultaneously with {@link #enumMapping()}.
*
- * @return An array of {@link FlagMap}, empty if not applicable
+ * @return An array of {@link FlagEntry}, empty if not applicable
* @see android.annotation.IntDef
* @see IntFlagMapping
*/
- FlagMap[] flagMapping() default {};
+ FlagEntry[] flagMapping() default {};
/**
@@ -113,7 +113,7 @@
@Target({TYPE})
@Retention(SOURCE)
@TestApi
- @interface EnumMap {
+ @interface EnumEntry {
/**
* The string name of this enumeration value.
*
@@ -138,7 +138,7 @@
@Target({TYPE})
@Retention(SOURCE)
@TestApi
- @interface FlagMap {
+ @interface FlagEntry {
/**
* The string name of this flag.
*
@@ -195,7 +195,7 @@
*
* This is inferred if {@link #enumMapping()} is specified.
*
- * @see EnumMap
+ * @see EnumEntry
* @hide
*/
@TestApi
@@ -206,7 +206,7 @@
*
* This is inferred if {@link #flagMapping()} is specified.
*
- * @see FlagMap
+ * @see FlagEntry
* @hide
*/
@TestApi
@@ -227,7 +227,7 @@
/**
* Value packs gravity information.
*
- * This type is not inferred, and is non-trivial to represent using {@link FlagMap}.
+ * This type is not inferred, and is non-trivial to represent using {@link FlagEntry}.
*
* @see android.view.Gravity
* @hide
diff --git a/core/java/android/view/inspector/InspectionCompanion.java b/core/java/android/view/inspector/InspectionCompanion.java
index 62d769b..a633a580 100644
--- a/core/java/android/view/inspector/InspectionCompanion.java
+++ b/core/java/android/view/inspector/InspectionCompanion.java
@@ -17,7 +17,6 @@
package android.view.inspector;
import android.annotation.NonNull;
-import android.annotation.Nullable;
/**
* An interface for companion objects used to inspect views.
@@ -33,11 +32,6 @@
* parent class via the parent's inspection companion, and the child companion will only read
* properties added or changed since the parent was defined.
*
- * Only one child traversal is considered for each class. If a descendant class defines a
- * different child traversal than its parent, only the bottom traversal is used. If a class does
- * not define its own child traversal, but one of its ancestors does, the bottom-most ancestor's
- * traversal will be used.
- *
* @param <T> The type of inspectable this is the companion to
*/
public interface InspectionCompanion<T> {
@@ -68,22 +62,6 @@
void readProperties(@NonNull T inspectable, @NonNull PropertyReader propertyReader);
/**
- * Get an optional name to display to developers for inspection nodes of this companion's type.
- *
- * The default implementation returns null, which will cause the runtime to use the class's
- * simple name as defined by {@link Class#getSimpleName()} as the node name.
- *
- * If the type of this companion is inflated from XML, this method should be overridden to
- * return the string used as the tag name for this type in XML.
- *
- * @return A string to use as the node name, or null to use the simple class name fallback.
- */
- @Nullable
- default String getNodeName() {
- return null;
- }
-
- /**
* Thrown by {@link #readProperties(Object, PropertyReader)} if called before
* {@link #mapProperties(PropertyMapper)}.
*/
diff --git a/core/java/android/view/inspector/IntEnumMapping.java b/core/java/android/view/inspector/IntEnumMapping.java
deleted file mode 100644
index 147bb46..0000000
--- a/core/java/android/view/inspector/IntEnumMapping.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 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 android.view.inspector;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.SparseArray;
-
-import java.util.Objects;
-
-/**
- * Maps the values of an {@code int} property to strings for properties that encode an enumeration.
- *
- * An {@link InspectionCompanion} may provide an instance of this class to a {@link PropertyMapper}
- * for flag values packed into primitive {@code int} properties.
- *
- * This class is an immutable wrapper for {@link SparseArray}, and must be constructed by a
- * {@link Builder}.
- *
- * @see PropertyMapper#mapIntEnum(String, int, IntEnumMapping)
- */
-public final class IntEnumMapping {
- private final SparseArray<String> mValues;
-
- /**
- * Get the name for the given property value
- *
- * @param value The value of the property
- * @return The name of the value in the enumeration, or null if no value is defined
- */
- @Nullable
- public String get(int value) {
- return mValues.get(value);
- }
-
- /**
- * Create a new instance from a builder.
- *
- * This constructor is private, use {@link Builder#build()} instead.
- *
- * @param builder A builder to create from
- */
- private IntEnumMapping(Builder builder) {
- mValues = builder.mValues.clone();
- }
-
- /**
- * A builder for {@link IntEnumMapping}.
- */
- public static final class Builder {
- @NonNull
- private SparseArray<String> mValues;
- private boolean mMustCloneValues = false;
-
- public Builder() {
- mValues = new SparseArray<>();
- }
-
- /**
- * Add a new enumerated value.
- *
- * @param name The string name of the enumeration value
- * @param value The {@code int} value of the enumeration value
- * @return This builder
- */
- @NonNull
- public Builder addValue(@NonNull String name, int value) {
- // Save an allocation, only re-clone if the builder is used again after building
- if (mMustCloneValues) {
- mValues = mValues.clone();
- }
-
- mValues.put(value, Objects.requireNonNull(name));
- return this;
- }
-
- /**
- * Build a new {@link IntEnumMapping} from this builder.
- *
- * @return A new mapping
- */
- @NonNull
- public IntEnumMapping build() {
- mMustCloneValues = true;
- return new IntEnumMapping(this);
- }
- }
-}
diff --git a/core/java/android/view/inspector/IntFlagMapping.java b/core/java/android/view/inspector/IntFlagMapping.java
index 2409081..f501329 100644
--- a/core/java/android/view/inspector/IntFlagMapping.java
+++ b/core/java/android/view/inspector/IntFlagMapping.java
@@ -21,6 +21,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -35,22 +36,20 @@
* it by bitwise anding it with the mask and comparing the result against the target, that is,
* {@code (value & mask) == target}.
*
- * This class is immutable, and must be constructed by a {@link Builder}.
- *
- * @see PropertyMapper#mapIntFlag(String, int, IntFlagMapping)
+ * @see PropertyMapper#mapIntFlag(String, int, java.util.function.IntFunction)
*/
public final class IntFlagMapping {
- private final Flag[] mFlags;
+ private final List<Flag> mFlags = new ArrayList<>();
/**
- * Get an array of the names of enabled flags for a given property value.
+ * Get a set of the names of enabled flags for a given property value.
*
* @param value The value of the property
* @return The names of the enabled flags, empty if no flags enabled
*/
@NonNull
public Set<String> get(int value) {
- final Set<String> enabledFlagNames = new HashSet<>(mFlags.length);
+ final Set<String> enabledFlagNames = new HashSet<>(mFlags.size());
for (Flag flag : mFlags) {
if (flag.isEnabledFor(value)) {
@@ -62,70 +61,14 @@
}
/**
- * Create a new instance from a builder.
+ * Add a mutually exclusive flag to the map.
*
- * This constructor is private, use {@link Builder#build()} instead.
- *
- * @param builder A builder to create from
+ * @param mask The bit mask to compare to and with a value
+ * @param target The target value to compare the masked value with
+ * @param name The name of the flag to include if enabled
*/
- private IntFlagMapping(Builder builder) {
- mFlags = builder.mFlags.toArray(new Flag[builder.mFlags.size()]);
- }
-
- /**
- * A builder for {@link IntFlagMapping}.
- */
- public static final class Builder {
- private ArrayList<Flag> mFlags;
-
- public Builder() {
- mFlags = new ArrayList<>();
- }
-
- /**
- * Add a new flag without a mask.
- *
- * The target value will be used as a mask, to handle the common case where flag values
- * are not mutually exclusive. The flag will be considered enabled for a property value if
- * the result of bitwise anding the target and the value equals the target, that is:
- * {@code (value & target) == target}.
- *
- * @param name The name of the flag
- * @param target The value to compare against
- * @return This builder
- */
- @NonNull
- public Builder addFlag(@NonNull String name, int target) {
- mFlags.add(new Flag(name, target, target));
- return this;
- }
-
- /**
- * Add a new flag with a mask.
- *
- * The flag will be considered enabled for a property value if the result of bitwise anding
- * the value and the mask equals the target, that is: {@code (value & mask) == target}.
- *
- * @param name The name of the flag
- * @param target The value to compare against
- * @param mask A bit mask
- * @return This builder
- */
- @NonNull
- public Builder addFlag(@NonNull String name, int target, int mask) {
- mFlags.add(new Flag(name, target, mask));
- return this;
- }
-
- /**
- * Build a new {@link IntFlagMapping} from this builder.
- *
- * @return A new mapping
- */
- @NonNull
- public IntFlagMapping build() {
- return new IntFlagMapping(this);
- }
+ public void add(int mask, int target, @NonNull String name) {
+ mFlags.add(new Flag(mask, target, name));
}
/**
@@ -136,10 +79,10 @@
private final int mTarget;
private final int mMask;
- private Flag(@NonNull String name, int target, int mask) {
- mName = Objects.requireNonNull(name);
+ private Flag(int mask, int target, @NonNull String name) {
mTarget = target;
mMask = mask;
+ mName = Objects.requireNonNull(name);
}
/**
diff --git a/core/java/android/view/inspector/PropertyMapper.java b/core/java/android/view/inspector/PropertyMapper.java
index 54d99df..cbc690e 100644
--- a/core/java/android/view/inspector/PropertyMapper.java
+++ b/core/java/android/view/inspector/PropertyMapper.java
@@ -19,6 +19,9 @@
import android.annotation.AttrRes;
import android.annotation.NonNull;
+import java.util.Set;
+import java.util.function.IntFunction;
+
/**
* An interface for mapping the string names of inspectable properties to integer identifiers.
*
@@ -154,7 +157,7 @@
int mapIntEnum(
@NonNull String name,
@AttrRes int attributeId,
- @NonNull IntEnumMapping mapping);
+ @NonNull IntFunction<String> mapping);
/**
* Map a string name to an integer ID for an attribute that contains resource IDs.
@@ -178,7 +181,7 @@
int mapIntFlag(
@NonNull String name,
@AttrRes int attributeId,
- @NonNull IntFlagMapping mapping);
+ @NonNull IntFunction<Set<String>> mapping);
/**
* Thrown from a map method if a property name is already mapped as different type.
*/
diff --git a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
index 17edf5c..9c268f2 100644
--- a/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
+++ b/core/java/android/view/textclassifier/ActionsSuggestionsHelper.java
@@ -23,10 +23,13 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Pair;
+import android.view.textclassifier.intent.LabeledIntent;
+import android.view.textclassifier.intent.TemplateIntentFactory;
import com.android.internal.annotations.VisibleForTesting;
import com.google.android.textclassifier.ActionsSuggestionsModel;
+import com.google.android.textclassifier.RemoteActionTemplate;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -46,6 +49,7 @@
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final class ActionsSuggestionsHelper {
+ private static final String TAG = "ActionsSuggestions";
private static final int USER_LOCAL = 0;
private static final int FIRST_NON_LOCAL_USER = 1;
@@ -117,8 +121,33 @@
}
/**
- * Returns a {@link android.view.textclassifier.LabeledIntent.TitleChooser} for
- * conversation actions use case.
+ * Generated labeled intent from an action suggestion and return the resolved result.
+ */
+ @Nullable
+ public static LabeledIntent.Result createLabeledIntentResult(
+ Context context,
+ TemplateIntentFactory templateIntentFactory,
+ ActionsSuggestionsModel.ActionSuggestion nativeSuggestion) {
+ RemoteActionTemplate[] remoteActionTemplates =
+ nativeSuggestion.getRemoteActionTemplates();
+ if (remoteActionTemplates == null) {
+ Log.w(TAG, "createRemoteAction: Missing template for type "
+ + nativeSuggestion.getActionType());
+ return null;
+ }
+ List<LabeledIntent> labeledIntents = templateIntentFactory.create(remoteActionTemplates);
+ if (labeledIntents.isEmpty()) {
+ return null;
+ }
+ // Given that we only support implicit intent here, we should expect there is just one
+ // intent for each action type.
+ LabeledIntent.TitleChooser titleChooser =
+ ActionsSuggestionsHelper.createTitleChooser(nativeSuggestion.getActionType());
+ return labeledIntents.get(0).resolve(context, titleChooser, null);
+ }
+
+ /**
+ * Returns a {@link LabeledIntent.TitleChooser} for conversation actions use case.
*/
@Nullable
public static LabeledIntent.TitleChooser createTitleChooser(String actionType) {
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index 2b952a3..f2d878a 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -92,10 +92,15 @@
*/
public static final String TYPE_SHARE_LOCATION = "share_location";
+ // TODO: Make this public API
/** @hide **/
public static final String TYPE_ADD_CONTACT = "add_contact";
- public static final @android.annotation.NonNull Creator<ConversationAction> CREATOR =
+ // TODO: Make this public API
+ /** @hide **/
+ public static final String TYPE_COPY = "copy";
+
+ public static final @NonNull Creator<ConversationAction> CREATOR =
new Creator<ConversationAction>() {
@Override
public ConversationAction createFromParcel(Parcel in) {
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index df548ae..eadad28 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.RemoteAction;
import android.content.Intent;
+import android.icu.util.ULocale;
import android.os.Bundle;
import java.util.ArrayList;
@@ -27,8 +28,10 @@
* Utility class for inserting and retrieving data in TextClassifier request/response extras.
* @hide
*/
+// TODO: Make this a TestApi for CTS testing.
public final class ExtrasUtils {
+ private static final String ENTITIES_EXTRAS = "entities-extras";
private static final String ACTION_INTENT = "action-intent";
private static final String ACTIONS_INTENTS = "actions-intents";
private static final String FOREIGN_LANGUAGE = "foreign-language";
@@ -36,6 +39,7 @@
private static final String SCORE = "score";
private static final String MODEL_VERSION = "model-version";
private static final String MODEL_NAME = "model-name";
+ private static final String TEXT_LANGUAGES = "text-languages";
private ExtrasUtils() {}
@@ -55,6 +59,8 @@
/**
* Stores {@code extra} as foreign language information in TextClassifier response object's
* extras {@code container}.
+ *
+ * @see #getForeignLanguageExtra(TextClassification)
*/
static void putForeignLanguageExtra(Bundle container, Bundle extra) {
container.putParcelable(FOREIGN_LANGUAGE, extra);
@@ -63,13 +69,68 @@
/**
* Returns foreign language detection information contained in the TextClassification object.
* responses.
+ *
+ * @see #putForeignLanguageExtra(Bundle, Bundle)
*/
@Nullable
- public static Bundle getForeignLanguageExtra(TextClassification classification) {
+ public static Bundle getForeignLanguageExtra(@Nullable TextClassification classification) {
+ if (classification == null) {
+ return null;
+ }
return classification.getExtras().getBundle(FOREIGN_LANGUAGE);
}
/**
+ * @see #getTopLanguage(Intent)
+ */
+ static void putTopLanguageScores(Bundle container, EntityConfidence languageScores) {
+ final int maxSize = Math.min(3, languageScores.getEntities().size());
+ final String[] languages = languageScores.getEntities().subList(0, maxSize)
+ .toArray(new String[0]);
+ final float[] scores = new float[languages.length];
+ for (int i = 0; i < languages.length; i++) {
+ scores[i] = languageScores.getConfidenceScore(languages[i]);
+ }
+ container.putStringArray(ENTITY_TYPE, languages);
+ container.putFloatArray(SCORE, scores);
+ }
+
+ /**
+ * @see #putTopLanguageScores(Bundle, EntityConfidence)
+ */
+ @Nullable
+ public static ULocale getTopLanguage(@Nullable Intent intent) {
+ if (intent == null) {
+ return null;
+ }
+ final Bundle tcBundle = intent.getBundleExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER);
+ if (tcBundle == null) {
+ return null;
+ }
+ final Bundle textLanguagesExtra = tcBundle.getBundle(TEXT_LANGUAGES);
+ if (textLanguagesExtra == null) {
+ return null;
+ }
+ final String[] languages = textLanguagesExtra.getStringArray(ENTITY_TYPE);
+ final float[] scores = textLanguagesExtra.getFloatArray(SCORE);
+ if (languages == null || scores == null
+ || languages.length == 0 || languages.length != scores.length) {
+ return null;
+ }
+ int highestScoringIndex = 0;
+ for (int i = 1; i < languages.length; i++) {
+ if (scores[highestScoringIndex] < scores[i]) {
+ highestScoringIndex = i;
+ }
+ }
+ return ULocale.forLanguageTag(languages[highestScoringIndex]);
+ }
+
+ public static void putTextLanguagesExtra(Bundle container, Bundle extra) {
+ container.putBundle(TEXT_LANGUAGES, extra);
+ }
+
+ /**
* Stores {@code actionIntents} information in TextClassifier response object's extras
* {@code container}.
*/
@@ -94,10 +155,37 @@
}
/**
+ * Stores {@code entities} information in TextClassifier response object's extras
+ * {@code container}.
+ *
+ * @see {@link #getCopyText(Bundle)}
+ */
+ public static void putEntitiesExtras(Bundle container, @Nullable Bundle entitiesExtras) {
+ container.putParcelable(ENTITIES_EXTRAS, entitiesExtras);
+ }
+
+ /**
+ * Returns {@code entities} information contained in a TextClassifier response object.
+ *
+ * @see {@link #putEntitiesExtras(Bundle, Bundle)}
+ */
+ @Nullable
+ public static String getCopyText(Bundle container) {
+ Bundle entitiesExtras = container.getParcelable(ENTITIES_EXTRAS);
+ if (entitiesExtras == null) {
+ return null;
+ }
+ return entitiesExtras.getString("text");
+ }
+
+ /**
* Returns {@code actionIntents} information contained in the TextClassification object.
*/
@Nullable
- public static ArrayList<Intent> getActionsIntents(TextClassification classification) {
+ public static ArrayList<Intent> getActionsIntents(@Nullable TextClassification classification) {
+ if (classification == null) {
+ return null;
+ }
return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS);
}
@@ -106,7 +194,11 @@
* action string, {@code intentAction}.
*/
@Nullable
- public static RemoteAction findAction(TextClassification classification, String intentAction) {
+ public static RemoteAction findAction(
+ @Nullable TextClassification classification, @Nullable String intentAction) {
+ if (classification == null || intentAction == null) {
+ return null;
+ }
final ArrayList<Intent> actionIntents = getActionsIntents(classification);
if (actionIntents != null) {
final int size = actionIntents.size();
@@ -124,7 +216,7 @@
* Returns the first "translate" action found in the {@code classification} object.
*/
@Nullable
- public static RemoteAction findTranslateAction(TextClassification classification) {
+ public static RemoteAction findTranslateAction(@Nullable TextClassification classification) {
return findAction(classification, Intent.ACTION_TRANSLATE);
}
@@ -132,7 +224,10 @@
* Returns the entity type contained in the {@code extra}.
*/
@Nullable
- public static String getEntityType(Bundle extra) {
+ public static String getEntityType(@Nullable Bundle extra) {
+ if (extra == null) {
+ return null;
+ }
return extra.getString(ENTITY_TYPE);
}
@@ -141,14 +236,21 @@
*/
@Nullable
public static float getScore(Bundle extra) {
- return extra.getFloat(SCORE, -1);
+ final int defaultValue = -1;
+ if (extra == null) {
+ return defaultValue;
+ }
+ return extra.getFloat(SCORE, defaultValue);
}
/**
* Returns the model name contained in the {@code extra}.
*/
@Nullable
- public static String getModelName(Bundle extra) {
+ public static String getModelName(@Nullable Bundle extra) {
+ if (extra == null) {
+ return null;
+ }
return extra.getString(MODEL_NAME);
}
}
diff --git a/core/java/android/view/textclassifier/Log.java b/core/java/android/view/textclassifier/Log.java
index 5c60c09..03ed496 100644
--- a/core/java/android/view/textclassifier/Log.java
+++ b/core/java/android/view/textclassifier/Log.java
@@ -22,8 +22,10 @@
* To enable full log:
* 1. adb shell setprop log.tag.androidtc VERBOSE
* 2. adb shell stop && adb shell start
+ *
+ * @hide
*/
-final class Log {
+public final class Log {
/**
* true: Enables full logging.
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index 38e72e3..876e5cc 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -50,6 +50,7 @@
* template_intent_factory_enabled (boolean)
* translate_in_classification_enabled (boolean)
* detect_languages_from_text_enabled (boolean)
+ * lang_id_context_settings (float[])
* </pre>
*
* <p>
@@ -58,12 +59,14 @@
*
* Example of setting the values for testing.
* adb shell settings put global text_classifier_constants \
- * model_dark_launch_enabled=true,smart_selection_enabled=true,\
- * entity_list_default=phone:address
+ * model_dark_launch_enabled=true,smart_selection_enabled=true, \
+ * entity_list_default=phone:address, \
+ * lang_id_context_settings=20:1.0:0.4
* @hide
*/
public final class TextClassificationConstants {
- private static final String LOG_TAG = "TextClassificationConstants";
+
+ private static final String LOG_TAG = TextClassifier.DEFAULT_LOG_TAG;
/**
* Whether the smart linkify feature is enabled.
@@ -148,7 +151,6 @@
* Whether to enable {@link android.view.textclassifier.TemplateIntentFactory}.
*/
private static final String TEMPLATE_INTENT_FACTORY_ENABLED = "template_intent_factory_enabled";
-
/**
* Whether to enable "translate" action in classifyText.
*/
@@ -160,6 +162,20 @@
*/
private static final String DETECT_LANGUAGES_FROM_TEXT_ENABLED =
"detect_languages_from_text_enabled";
+ /**
+ * A colon(:) separated string that specifies the configuration to use when including
+ * surrounding context text in language detection queries.
+ * <p>
+ * Format= minimumTextSize<int>:penalizeRatio<float>:textScoreRatio<float>
+ * <p>
+ * e.g. 20:1.0:0.4
+ * <p>
+ * Accept all text lengths with minimumTextSize=0
+ * <p>
+ * Reject all text less than minimumTextSize with penalizeRatio=0
+ * @see {@code TextClassifierImpl#detectLanguages(String, int, int)} for reference.
+ */
+ private static final String LANG_ID_CONTEXT_SETTINGS = "lang_id_context_settings";
private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -193,6 +209,7 @@
.add(ConversationAction.TYPE_VIEW_CALENDAR)
.add(ConversationAction.TYPE_VIEW_MAP)
.add(ConversationAction.TYPE_ADD_CONTACT)
+ .add(ConversationAction.TYPE_COPY)
.toString();
/**
* < 0 : Not set. Use value from LangId model.
@@ -204,6 +221,8 @@
private static final boolean TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT = true;
private static final boolean TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT = true;
private static final boolean DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT = true;
+ private static final String LANG_ID_CONTEXT_SETTINGS_DEFAULT =
+ new StringJoiner(STRING_LIST_DELIMITER).add("20").add("1.0").add("0.4").toString();
private final boolean mSystemTextClassifierEnabled;
private final boolean mLocalTextClassifierEnabled;
@@ -225,6 +244,7 @@
private final boolean mTemplateIntentFactoryEnabled;
private final boolean mTranslateInClassificationEnabled;
private final boolean mDetectLanguagesFromTextEnabled;
+ private final float[] mLangIdContextSettings;
private TextClassificationConstants(@Nullable String settings) {
ConfigParser configParser = new ConfigParser(settings);
@@ -272,9 +292,10 @@
configParser.getInt(
GENERATE_LINKS_LOG_SAMPLE_RATE,
GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
- mEntityListDefault = parseStringList(configParser.getString(
- ENTITY_LIST_DEFAULT,
- ENTITY_LIST_DEFAULT_VALUE));
+ mEntityListDefault = parseStringList(
+ configParser.getString(
+ ENTITY_LIST_DEFAULT,
+ ENTITY_LIST_DEFAULT_VALUE));
mEntityListNotEditable = parseStringList(
configParser.getString(
ENTITY_LIST_NOT_EDITABLE,
@@ -295,13 +316,22 @@
configParser.getFloat(
LANG_ID_THRESHOLD_OVERRIDE,
LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
- mTemplateIntentFactoryEnabled = configParser.getBoolean(
- TEMPLATE_INTENT_FACTORY_ENABLED,
- TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
- mTranslateInClassificationEnabled = configParser.getBoolean(
- TRANSLATE_IN_CLASSIFICATION_ENABLED, TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
- mDetectLanguagesFromTextEnabled = configParser.getBoolean(
- DETECT_LANGUAGES_FROM_TEXT_ENABLED, DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
+ mTemplateIntentFactoryEnabled =
+ configParser.getBoolean(
+ TEMPLATE_INTENT_FACTORY_ENABLED,
+ TEMPLATE_INTENT_FACTORY_ENABLED_DEFAULT);
+ mTranslateInClassificationEnabled =
+ configParser.getBoolean(
+ TRANSLATE_IN_CLASSIFICATION_ENABLED,
+ TRANSLATE_IN_CLASSIFICATION_ENABLED_DEFAULT);
+ mDetectLanguagesFromTextEnabled =
+ configParser.getBoolean(
+ DETECT_LANGUAGES_FROM_TEXT_ENABLED,
+ DETECT_LANGUAGES_FROM_TEXT_ENABLED_DEFAULT);
+ mLangIdContextSettings = parseFloatArray(
+ configParser,
+ LANG_ID_CONTEXT_SETTINGS,
+ LANG_ID_CONTEXT_SETTINGS_DEFAULT);
}
/** Load from a settings string. */
@@ -389,10 +419,35 @@
return mDetectLanguagesFromTextEnabled;
}
+ public float[] getLangIdContextSettings() {
+ return mLangIdContextSettings;
+ }
+
private static List<String> parseStringList(String listStr) {
return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
}
+ private static float[] parseFloatArray(
+ ConfigParser configParser, String key, String defaultStr) {
+ final String str = configParser.getString(key, defaultStr);
+ final String[] defaultSplit = defaultStr.split(STRING_LIST_DELIMITER);
+ String[] split = str.split(STRING_LIST_DELIMITER);
+ if (split.length != defaultSplit.length) {
+ Log.v(LOG_TAG, "Error parsing " + key + " flag. Using defaults.");
+ split = defaultSplit;
+ }
+ final float[] result = new float[split.length];
+ for (int i = 0; i < split.length; i++) {
+ try {
+ result[i] = Float.parseFloat(split[i]);
+ } catch (NumberFormatException e) {
+ Log.v(LOG_TAG, "Error parsing part of " + key + " flag. Using defaults.");
+ result[i] = Float.parseFloat(defaultSplit[i]);
+ }
+ }
+ return result;
+ }
+
void dump(IndentingPrintWriter pw) {
pw.println("TextClassificationConstants:");
pw.increaseIndent();
@@ -417,6 +472,7 @@
pw.printPair("isTemplateIntentFactoryEnabled", mTemplateIntentFactoryEnabled);
pw.printPair("isTranslateInClassificationEnabled", mTranslateInClassificationEnabled);
pw.printPair("isDetectLanguageFromTextEnabled", mDetectLanguagesFromTextEnabled);
+ pw.printPair("getLangIdContextSettings", Arrays.toString(mLangIdContextSettings));
pw.decreaseIndent();
pw.println();
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index a4e5502..ac8a429 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -33,11 +33,13 @@
import android.text.util.Linkify.LinkifyMask;
import android.util.ArrayMap;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -644,11 +646,14 @@
* <li>Provides validation of input parameters to TextClassifier methods
* </ul>
*
- * Intended to be used only in this package.
+ * Intended to be used only for TextClassifier purposes.
* @hide
*/
final class Utils {
+ @GuardedBy("WORD_ITERATOR")
+ private static final BreakIterator WORD_ITERATOR = BreakIterator.getWordInstance();
+
/**
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or is not greater than startIndex;
@@ -666,6 +671,47 @@
}
/**
+ * Returns the substring of {@code text} that contains at least text from index
+ * {@code start} <i>(inclusive)</i> to index {@code end} <i><(exclusive)/i> with the goal of
+ * returning text that is at least {@code minimumLength}. If {@code text} is not long
+ * enough, this will return {@code text}. This method returns text at word boundaries.
+ *
+ * @param text the source text
+ * @param start the start index of text that must be included
+ * @param end the end index of text that must be included
+ * @param minimumLength minimum length of text to return if {@code text} is long enough
+ */
+ public static String getSubString(
+ String text, int start, int end, int minimumLength) {
+ Preconditions.checkArgument(start >= 0);
+ Preconditions.checkArgument(end <= text.length());
+ Preconditions.checkArgument(start <= end);
+
+ if (text.length() < minimumLength) {
+ return text;
+ }
+
+ final int length = end - start;
+ if (length >= minimumLength) {
+ return text.substring(start, end);
+ }
+
+ final int offset = (minimumLength - length) / 2;
+ int iterStart = Math.max(0, Math.min(start - offset, text.length() - minimumLength));
+ int iterEnd = Math.min(text.length(), iterStart + minimumLength);
+
+ synchronized (WORD_ITERATOR) {
+ WORD_ITERATOR.setText(text);
+ iterStart = WORD_ITERATOR.isBoundary(iterStart)
+ ? iterStart : Math.max(0, WORD_ITERATOR.preceding(iterStart));
+ iterEnd = WORD_ITERATOR.isBoundary(iterEnd)
+ ? iterEnd : Math.max(iterEnd, WORD_ITERATOR.following(iterEnd));
+ WORD_ITERATOR.setText("");
+ return text.substring(iterStart, iterEnd);
+ }
+ }
+
+ /**
* Generates links using legacy {@link Linkify}.
*/
public static TextLinks generateLegacyLinks(@NonNull TextLinks.Request request) {
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 0f3a8cf..8f5f0a37 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -21,10 +21,19 @@
import android.annotation.WorkerThread;
import android.app.RemoteAction;
import android.content.Context;
+import android.content.Intent;
import android.icu.util.ULocale;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.ParcelFileDescriptor;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
+import android.view.textclassifier.intent.ClassificationIntentFactory;
+import android.view.textclassifier.intent.LabeledIntent;
+import android.view.textclassifier.intent.LegacyClassificationIntentFactory;
+import android.view.textclassifier.intent.TemplateClassificationIntentFactory;
+import android.view.textclassifier.intent.TemplateIntentFactory;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
@@ -33,6 +42,7 @@
import com.google.android.textclassifier.ActionsSuggestionsModel;
import com.google.android.textclassifier.AnnotatorModel;
import com.google.android.textclassifier.LangIdModel;
+import com.google.android.textclassifier.LangIdModel.LanguageResult;
import java.io.File;
import java.io.FileNotFoundException;
@@ -41,11 +51,12 @@
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* Default implementation of the {@link TextClassifier} interface.
@@ -85,19 +96,19 @@
private final Object mLock = new Object();
- @GuardedBy("mLock") // Do not access outside this lock.
+ @GuardedBy("mLock")
private ModelFileManager.ModelFile mAnnotatorModelInUse;
- @GuardedBy("mLock") // Do not access outside this lock.
+ @GuardedBy("mLock")
private AnnotatorModel mAnnotatorImpl;
- @GuardedBy("mLock") // Do not access outside this lock.
+ @GuardedBy("mLock")
private ModelFileManager.ModelFile mLangIdModelInUse;
- @GuardedBy("mLock") // Do not access outside this lock.
+ @GuardedBy("mLock")
private LangIdModel mLangIdImpl;
- @GuardedBy("mLock") // Do not access outside this lock.
+ @GuardedBy("mLock")
private ModelFileManager.ModelFile mActionModelInUse;
- @GuardedBy("mLock") // Do not access outside this lock.
+ @GuardedBy("mLock")
private ActionsSuggestionsModel mActionsImpl;
private final SelectionSessionLogger mSessionLogger = new SelectionSessionLogger();
@@ -110,7 +121,7 @@
private final ModelFileManager mLangIdModelFileManager;
private final ModelFileManager mActionsModelFileManager;
- private final IntentFactory mIntentFactory;
+ private final ClassificationIntentFactory mClassificationIntentFactory;
private final TemplateIntentFactory mTemplateIntentFactory;
public TextClassifierImpl(
@@ -142,10 +153,10 @@
ActionsSuggestionsModel::getLocales));
mTemplateIntentFactory = new TemplateIntentFactory();
- mIntentFactory = mSettings.isTemplateIntentFactoryEnabled()
+ mClassificationIntentFactory = mSettings.isTemplateIntentFactoryEnabled()
? new TemplateClassificationIntentFactory(
- mTemplateIntentFactory, new LegacyIntentFactory())
- : new LegacyIntentFactory();
+ mTemplateIntentFactory, new LegacyClassificationIntentFactory())
+ : new LegacyClassificationIntentFactory();
}
public TextClassifierImpl(Context context, TextClassificationConstants settings) {
@@ -278,7 +289,7 @@
final ZonedDateTime refTime = ZonedDateTime.now();
final Collection<String> entitiesToIdentify = request.getEntityConfig() != null
? request.getEntityConfig().resolveEntityListModifications(
- getEntitiesForHints(request.getEntityConfig().getHints()))
+ getEntitiesForHints(request.getEntityConfig().getHints()))
: mSettings.getEntityListDefault();
final String localesString = concatenateLocales(request.getDefaultLocales());
final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
@@ -299,7 +310,7 @@
|| !entitiesToIdentify.contains(results[0].getCollection())) {
continue;
}
- final Map<String, Float> entityScores = new HashMap<>();
+ final Map<String, Float> entityScores = new ArrayMap<>();
for (int i = 0; i < results.length; i++) {
entityScores.put(results[i].getCollection(), results[i].getScore());
}
@@ -435,21 +446,20 @@
if (!expectedTypes.contains(actionType)) {
continue;
}
- List<LabeledIntent> labeledIntents =
- mTemplateIntentFactory.create(nativeSuggestion.getRemoteActionTemplates());
- Bundle extras = new Bundle();
+ LabeledIntent.Result labeledIntentResult =
+ ActionsSuggestionsHelper.createLabeledIntentResult(
+ mContext,
+ mTemplateIntentFactory,
+ nativeSuggestion);
RemoteAction remoteAction = null;
- // Given that we only support implicit intent here, we should expect there is just one
- // intent for each action type.
- if (!labeledIntents.isEmpty()) {
- LabeledIntent.TitleChooser titleChooser =
- ActionsSuggestionsHelper.createTitleChooser(actionType);
- LabeledIntent.Result result = labeledIntents.get(0).resolve(mContext, titleChooser);
- if (result != null) {
- remoteAction = result.remoteAction;
- ExtrasUtils.putActionIntent(extras, result.resolvedIntent);
- }
+ Bundle extras = new Bundle();
+ if (labeledIntentResult != null) {
+ remoteAction = labeledIntentResult.remoteAction;
+ ExtrasUtils.putActionIntent(extras, labeledIntentResult.resolvedIntent);
}
+ ExtrasUtils.putEntitiesExtras(
+ extras,
+ TemplateIntentFactory.nameVariantsToBundle(nativeSuggestion.getEntityData()));
conversationActions.add(
new ConversationAction.Builder(actionType)
.setConfidenceScore(nativeSuggestion.getScore())
@@ -616,50 +626,67 @@
}
}
- final Bundle foreignLanguageBundle = detectForeignLanguage(classifiedText);
+ final Pair<Bundle, Bundle> languagesBundles = generateLanguageBundles(text, start, end);
+ final Bundle textLanguagesBundle = languagesBundles.first;
+ final Bundle foreignLanguageBundle = languagesBundles.second;
builder.setForeignLanguageExtra(foreignLanguageBundle);
boolean isPrimaryAction = true;
- List<LabeledIntent> labeledIntents = mIntentFactory.create(
+ final List<LabeledIntent> labeledIntents = mClassificationIntentFactory.create(
mContext,
classifiedText,
foreignLanguageBundle != null,
referenceTime,
highestScoringResult);
- LabeledIntent.TitleChooser titleChooser =
+ final LabeledIntent.TitleChooser titleChooser =
(labeledIntent, resolveInfo) -> labeledIntent.titleWithoutEntity;
+
for (LabeledIntent labeledIntent : labeledIntents) {
- LabeledIntent.Result result = labeledIntent.resolve(mContext, titleChooser);
+ final LabeledIntent.Result result =
+ labeledIntent.resolve(mContext, titleChooser, textLanguagesBundle);
if (result == null) {
continue;
}
+
+ final Intent intent = result.resolvedIntent;
final RemoteAction action = result.remoteAction;
if (isPrimaryAction) {
// For O backwards compatibility, the first RemoteAction is also written to the
// legacy API fields.
builder.setIcon(action.getIcon().loadDrawable(mContext));
builder.setLabel(action.getTitle().toString());
- builder.setIntent(result.resolvedIntent);
+ builder.setIntent(intent);
builder.setOnClickListener(TextClassification.createIntentOnClickListener(
- TextClassification.createPendingIntent(mContext,
- result.resolvedIntent, labeledIntent.requestCode)));
+ TextClassification.createPendingIntent(
+ mContext, intent, labeledIntent.requestCode)));
isPrimaryAction = false;
}
- builder.addAction(action, result.resolvedIntent);
+ builder.addAction(action, intent);
}
return builder.setId(createId(text, start, end)).build();
}
/**
- * Returns a bundle with the language and confidence score if it finds the text to be
- * in a foreign language. Otherwise returns null. This algorithm defines what the system thinks
- * is a foreign language.
+ * Returns a bundle pair with language detection information for extras.
+ * <p>
+ * Pair.first = textLanguagesBundle - A bundle containing information about all detected
+ * languages in the text. May be null if language detection fails or is disabled. This is
+ * typically expected to be added to a textClassifier generated remote action intent.
+ * See {@link ExtrasUtils#putTextLanguagesExtra(Bundle, Bundle)}.
+ * See {@link ExtrasUtils#getTopLanguage(Intent)}.
+ * <p>
+ * Pair.second = foreignLanguageBundle - A bundle with the language and confidence score if the
+ * system finds the text to be in a foreign language. Otherwise is null.
+ * See {@link TextClassification.Builder#setForeignLanguageExtra(Bundle)}.
+ *
+ * @param context the context of the text to detect languages for
+ * @param start the start index of the text
+ * @param end the end index of the text
*/
// TODO: Revisit this algorithm.
// TODO: Consider making this public API.
- @Nullable
- private Bundle detectForeignLanguage(String text) {
+ private Pair<Bundle, Bundle> generateLanguageBundles(String context, int start, int end) {
if (!mSettings.isTranslateInClassificationEnabled()) {
return null;
}
@@ -668,42 +695,118 @@
if (threshold < 0 || threshold > 1) {
Log.w(LOG_TAG,
"[detectForeignLanguage] unexpected threshold is found: " + threshold);
- return null;
+ return Pair.create(null, null);
}
- final LangIdModel langId = getLangIdImpl();
- final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
- if (langResults.length <= 0) {
- return null;
+ final EntityConfidence languageScores = detectLanguages(context, start, end);
+ if (languageScores.getEntities().isEmpty()) {
+ return Pair.create(null, null);
}
- LangIdModel.LanguageResult highestScoringResult = langResults[0];
- for (int i = 1; i < langResults.length; i++) {
- if (langResults[i].getScore() > highestScoringResult.getScore()) {
- highestScoringResult = langResults[i];
- }
- }
- if (highestScoringResult.getScore() < threshold) {
- return null;
+ final Bundle textLanguagesBundle = new Bundle();
+ ExtrasUtils.putTopLanguageScores(textLanguagesBundle, languageScores);
+
+ final String language = languageScores.getEntities().get(0);
+ final float score = languageScores.getConfidenceScore(language);
+ if (score < threshold) {
+ return Pair.create(textLanguagesBundle, null);
}
- Log.v(LOG_TAG, String.format("Language detected: <%s:%s>",
- highestScoringResult.getLanguage(), highestScoringResult.getScore()));
+ Log.v(LOG_TAG, String.format(
+ Locale.US, "Language detected: <%s:%.2f>", language, score));
- final Locale detected = new Locale(highestScoringResult.getLanguage());
+ final Locale detected = new Locale(language);
final LocaleList deviceLocales = LocaleList.getDefault();
final int size = deviceLocales.size();
for (int i = 0; i < size; i++) {
if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) {
- return null;
+ return Pair.create(textLanguagesBundle, null);
}
}
- return ExtrasUtils.createForeignLanguageExtra(
- detected.getLanguage(), highestScoringResult.getScore(), langId.getVersion());
+ final Bundle foreignLanguageBundle = ExtrasUtils.createForeignLanguageExtra(
+ detected.getLanguage(), score, getLangIdImpl().getVersion());
+ return Pair.create(textLanguagesBundle, foreignLanguageBundle);
} catch (Throwable t) {
- Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t);
+ Log.e(LOG_TAG, "Error generating language bundles.", t);
}
- return null;
+ return Pair.create(null, null);
+ }
+
+ /**
+ * Detect the language of a piece of text by taking surrounding text into consideration.
+ *
+ * @param text text providing context for the text for which its language is to be detected
+ * @param start the start index of the text to detect its language
+ * @param end the end index of the text to detect its language
+ */
+ // TODO: Revisit this algorithm.
+ private EntityConfidence detectLanguages(String text, int start, int end)
+ throws FileNotFoundException {
+ Preconditions.checkArgument(start >= 0);
+ Preconditions.checkArgument(end <= text.length());
+ Preconditions.checkArgument(start <= end);
+
+ final float[] langIdContextSettings = mSettings.getLangIdContextSettings();
+ // The minimum size of text to prefer for detection.
+ final int minimumTextSize = (int) langIdContextSettings[0];
+ // For reducing the score when text is less than the preferred size.
+ final float penalizeRatio = langIdContextSettings[1];
+ // Original detection score to surrounding text detection score ratios.
+ final float subjectTextScoreRatio = langIdContextSettings[2];
+ final float moreTextScoreRatio = 1f - subjectTextScoreRatio;
+ Log.v(LOG_TAG,
+ String.format(Locale.US, "LangIdContextSettings: "
+ + "minimumTextSize=%d, penalizeRatio=%.2f, "
+ + "subjectTextScoreRatio=%.2f, moreTextScoreRatio=%.2f",
+ minimumTextSize, penalizeRatio, subjectTextScoreRatio, moreTextScoreRatio));
+
+ if (end - start < minimumTextSize && penalizeRatio <= 0) {
+ return new EntityConfidence(Collections.emptyMap());
+ }
+
+ final String subject = text.substring(start, end);
+ final EntityConfidence scores = detectLanguages(subject);
+
+ if (subject.length() >= minimumTextSize
+ || subject.length() == text.length()
+ || subjectTextScoreRatio * penalizeRatio >= 1) {
+ return scores;
+ }
+
+ final EntityConfidence moreTextScores;
+ if (moreTextScoreRatio >= 0) {
+ // Attempt to grow the detection text to be at least minimumTextSize long.
+ final String moreText = Utils.getSubString(text, start, end, minimumTextSize);
+ moreTextScores = detectLanguages(moreText);
+ } else {
+ moreTextScores = new EntityConfidence(Collections.emptyMap());
+ }
+
+ // Combine the original detection scores with the those returned after including more text.
+ final Map<String, Float> newScores = new ArrayMap<>();
+ final Set<String> languages = new ArraySet<>();
+ languages.addAll(scores.getEntities());
+ languages.addAll(moreTextScores.getEntities());
+ for (String language : languages) {
+ final float score = (subjectTextScoreRatio * scores.getConfidenceScore(language)
+ + moreTextScoreRatio * moreTextScores.getConfidenceScore(language))
+ * penalizeRatio;
+ newScores.put(language, score);
+ }
+ return new EntityConfidence(newScores);
+ }
+
+ /**
+ * Detect languages for the specified text.
+ */
+ private EntityConfidence detectLanguages(String text) throws FileNotFoundException {
+ final LangIdModel langId = getLangIdImpl();
+ final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
+ final Map<String, Float> languagesMap = new ArrayMap<>();
+ for (LanguageResult langResult : langResults) {
+ languagesMap.put(langResult.getLanguage(), langResult.getScore());
+ }
+ return new EntityConfidence(languagesMap);
}
private float getLangIdThreshold() {
diff --git a/core/java/android/view/textclassifier/IntentFactory.java b/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
similarity index 89%
rename from core/java/android/view/textclassifier/IntentFactory.java
rename to core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
index 722c812..b034846 100644
--- a/core/java/android/view/textclassifier/IntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/ClassificationIntentFactory.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import android.annotation.Nullable;
import android.content.Context;
@@ -27,7 +27,7 @@
/**
* @hide
*/
-public interface IntentFactory {
+public interface ClassificationIntentFactory {
/**
* Return a list of LabeledIntent from the classification result.
@@ -51,8 +51,7 @@
new Intent(Intent.ACTION_TRANSLATE)
// TODO: Probably better to introduce a "translate" scheme instead of
// using EXTRA_TEXT.
- .putExtra(Intent.EXTRA_TEXT, text)
- .putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true),
+ .putExtra(Intent.EXTRA_TEXT, text),
text.hashCode()));
}
}
diff --git a/core/java/android/view/textclassifier/LabeledIntent.java b/core/java/android/view/textclassifier/intent/LabeledIntent.java
similarity index 81%
rename from core/java/android/view/textclassifier/LabeledIntent.java
rename to core/java/android/view/textclassifier/intent/LabeledIntent.java
index d2897b2..11d64f1 100644
--- a/core/java/android/view/textclassifier/LabeledIntent.java
+++ b/core/java/android/view/textclassifier/intent/LabeledIntent.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -24,7 +24,12 @@
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
import android.text.TextUtils;
+import android.view.textclassifier.ExtrasUtils;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassifier;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
@@ -85,10 +90,16 @@
/**
* Return the resolved result.
+ *
+ * @param context the context to resolve the result's intent and action
+ * @param titleChooser for choosing an action title
+ * @param textLanguagesBundle containing language detection information
*/
@Nullable
public Result resolve(
- Context context, @Nullable TitleChooser titleChooser) {
+ Context context,
+ @Nullable TitleChooser titleChooser,
+ @Nullable Bundle textLanguagesBundle) {
final PackageManager pm = context.getPackageManager();
final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0);
@@ -104,6 +115,10 @@
}
Intent resolvedIntent = new Intent(intent);
resolvedIntent.setComponent(new ComponentName(packageName, className));
+ resolvedIntent.putExtra(
+ TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER,
+ getFromTextClassifierExtra(textLanguagesBundle));
+
boolean shouldShowIcon = false;
Icon icon = null;
if (!"android".equals(packageName)) {
@@ -115,25 +130,32 @@
}
if (icon == null) {
// RemoteAction requires that there be an icon.
- icon = Icon.createWithResource("android",
- com.android.internal.R.drawable.ic_more_items);
+ icon = Icon.createWithResource(
+ "android", com.android.internal.R.drawable.ic_more_items);
}
final PendingIntent pendingIntent =
TextClassification.createPendingIntent(context, resolvedIntent, requestCode);
- if (titleChooser == null) {
- titleChooser = DEFAULT_TITLE_CHOOSER;
- }
+ titleChooser = titleChooser == null ? DEFAULT_TITLE_CHOOSER : titleChooser;
CharSequence title = titleChooser.chooseTitle(this, resolveInfo);
if (TextUtils.isEmpty(title)) {
Log.w(TAG, "Custom titleChooser return null, fallback to the default titleChooser");
title = DEFAULT_TITLE_CHOOSER.chooseTitle(this, resolveInfo);
}
- final RemoteAction action =
- new RemoteAction(icon, title, description, pendingIntent);
+ final RemoteAction action = new RemoteAction(icon, title, description, pendingIntent);
action.setShouldShowIcon(shouldShowIcon);
return new Result(resolvedIntent, action);
}
+ private Bundle getFromTextClassifierExtra(@Nullable Bundle textLanguagesBundle) {
+ if (textLanguagesBundle != null) {
+ final Bundle bundle = new Bundle();
+ ExtrasUtils.putTextLanguagesExtra(bundle, textLanguagesBundle);
+ return bundle;
+ } else {
+ return Bundle.EMPTY;
+ }
+ }
+
/**
* Data class that holds the result.
*/
diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
similarity index 96%
rename from core/java/android/view/textclassifier/LegacyIntentFactory.java
rename to core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
index ea9229d..7916791 100644
--- a/core/java/android/view/textclassifier/LegacyIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/LegacyClassificationIntentFactory.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import static java.time.temporal.ChronoUnit.MILLIS;
@@ -29,6 +29,8 @@
import android.provider.Browser;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassifier;
import com.google.android.textclassifier.AnnotatorModel;
@@ -44,14 +46,12 @@
* Creates intents based on the classification type.
* @hide
*/
-public final class LegacyIntentFactory implements IntentFactory {
+public final class LegacyClassificationIntentFactory implements ClassificationIntentFactory {
- private static final String TAG = "LegacyIntentFactory";
+ private static final String TAG = "LegacyClassificationIntentFactory";
private static final long MIN_EVENT_FUTURE_MILLIS = TimeUnit.MINUTES.toMillis(5);
private static final long DEFAULT_EVENT_DURATION = TimeUnit.HOURS.toMillis(1);
- public LegacyIntentFactory() {}
-
@NonNull
@Override
public List<LabeledIntent> create(Context context, String text, boolean foreignText,
@@ -96,10 +96,8 @@
break;
}
if (foreignText) {
- IntentFactory.insertTranslateAction(actions, context, text);
+ ClassificationIntentFactory.insertTranslateAction(actions, context, text);
}
- actions.forEach(
- action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
return actions;
}
diff --git a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
similarity index 82%
rename from core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
rename to core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
index ed0259f..111fc6a 100644
--- a/core/java/android/view/textclassifier/TemplateClassificationIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/TemplateClassificationIntentFactory.java
@@ -13,14 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassifier;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
import com.google.android.textclassifier.AnnotatorModel;
@@ -36,19 +37,19 @@
* @hide
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public final class TemplateClassificationIntentFactory implements IntentFactory {
+public final class TemplateClassificationIntentFactory implements ClassificationIntentFactory {
private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
private final TemplateIntentFactory mTemplateIntentFactory;
- private final IntentFactory mFallback;
+ private final ClassificationIntentFactory mFallback;
public TemplateClassificationIntentFactory(TemplateIntentFactory templateIntentFactory,
- IntentFactory fallback) {
+ ClassificationIntentFactory fallback) {
mTemplateIntentFactory = Preconditions.checkNotNull(templateIntentFactory);
mFallback = Preconditions.checkNotNull(fallback);
}
/**
- * Returns a list of {@link android.view.textclassifier.LabeledIntent}
+ * Returns a list of {@link LabeledIntent}
* that are constructed from the classification result.
*/
@NonNull
@@ -63,15 +64,16 @@
return Collections.emptyList();
}
RemoteActionTemplate[] remoteActionTemplates = classification.getRemoteActionTemplates();
- if (ArrayUtils.isEmpty(remoteActionTemplates)) {
+ if (remoteActionTemplates == null) {
// RemoteActionTemplate is missing, fallback.
- Log.w(TAG, "RemoteActionTemplate is missing, fallback to LegacyIntentFactory.");
+ Log.w(TAG, "RemoteActionTemplate is missing, fallback to"
+ + " LegacyClassificationIntentFactory.");
return mFallback.create(context, text, foreignText, referenceTime, classification);
}
final List<LabeledIntent> labeledIntents =
mTemplateIntentFactory.create(remoteActionTemplates);
if (foreignText) {
- IntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
+ ClassificationIntentFactory.insertTranslateAction(labeledIntents, context, text.trim());
}
return labeledIntents;
}
diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
similarity index 87%
rename from core/java/android/view/textclassifier/TemplateIntentFactory.java
rename to core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
index 0696d98..59cd7ab 100644
--- a/core/java/android/view/textclassifier/TemplateIntentFactory.java
+++ b/core/java/android/view/textclassifier/intent/TemplateIntentFactory.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -21,15 +21,15 @@
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
+import android.view.textclassifier.Log;
+import android.view.textclassifier.TextClassifier;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.google.android.textclassifier.NamedVariant;
import com.google.android.textclassifier.RemoteActionTemplate;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
/**
@@ -41,11 +41,14 @@
public final class TemplateIntentFactory {
private static final String TAG = TextClassifier.DEFAULT_LOG_TAG;
- @NonNull
+ /**
+ * Constructs and returns a list of {@link LabeledIntent} based on the given templates.
+ */
+ @Nullable
public List<LabeledIntent> create(
- @Nullable RemoteActionTemplate[] remoteActionTemplates) {
- if (ArrayUtils.isEmpty(remoteActionTemplates)) {
- return Collections.emptyList();
+ @NonNull RemoteActionTemplate[] remoteActionTemplates) {
+ if (remoteActionTemplates.length == 0) {
+ return new ArrayList<>();
}
final List<LabeledIntent> labeledIntents = new ArrayList<>();
for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
@@ -63,8 +66,6 @@
? LabeledIntent.DEFAULT_REQUEST_CODE
: remoteActionTemplate.requestCode));
}
- labeledIntents.forEach(
- action -> action.intent.putExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, true));
return labeledIntents;
}
@@ -108,11 +109,14 @@
}
}
}
- intent.putExtras(createExtras(remoteActionTemplate.extras));
+ intent.putExtras(nameVariantsToBundle(remoteActionTemplate.extras));
return intent;
}
- private static Bundle createExtras(NamedVariant[] namedVariants) {
+ /**
+ * Converts an array of {@link NamedVariant} to a Bundle and returns it.
+ */
+ public static Bundle nameVariantsToBundle(@Nullable NamedVariant[] namedVariants) {
if (namedVariants == null) {
return Bundle.EMPTY;
}
@@ -142,7 +146,8 @@
break;
default:
Log.w(TAG,
- "Unsupported type found in createExtras : " + namedVariant.getType());
+ "Unsupported type found in nameVariantsToBundle : "
+ + namedVariant.getType());
}
}
return bundle;
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 494eb03..a46580d 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -245,10 +245,11 @@
/**
* Used with {@link #setForceDark}
*
- * Enable force dark, dependent on the state of the WebView parent. If the WebView parent view
- * is being automatically rendered in dark mode, then WebView content will be rendered so as to
- * emulate a dark theme. WebViews that are not attached to the view hierarchy will not be
- * inverted.
+ * Enable force dark dependent on the state of the WebView parent view. If the WebView parent
+ * view is being automatically force darkened
+ * (see: {@link android.view.View#setForceDarkAllowed}), then WebView content will be rendered
+ * so as to emulate a dark theme. WebViews that are not attached to the view hierarchy will not
+ * be inverted.
*/
public static final int FORCE_DARK_AUTO = 1;
@@ -1466,6 +1467,8 @@
/**
* Set the force dark mode for this WebView.
+ *
+ * @param forceDark the force dark mode to set.
*/
public void setForceDark(@ForceDark int forceDark) {
// Stub implementation to satisfy Roboelectrc shadows that don't override this yet.
@@ -1474,6 +1477,8 @@
/**
* Get the force dark mode for this WebView.
*
+ * The default force dark mode is {@link #FORCE_DARK_AUTO}
+ *
* @return the currently set force dark mode.
*/
public @ForceDark int getForceDark() {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 034cabd..26dba45 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2292,9 +2292,9 @@
* @return the requested renderer priority policy.
*/
@InspectableProperty(hasAttributeId = false, enumMapping = {
- @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED),
- @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND),
- @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
+ @InspectableProperty.EnumEntry(name = "waived", value = RENDERER_PRIORITY_WAIVED),
+ @InspectableProperty.EnumEntry(name = "bound", value = RENDERER_PRIORITY_BOUND),
+ @InspectableProperty.EnumEntry(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
})
@RendererPriority
public int getRendererRequestedPriority() {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 6d88530..4413585 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -448,8 +448,9 @@
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
- initialApplication.getAssets().addAssetPathAsSharedLibrary(
- webViewContext.getApplicationInfo().sourceDir);
+ for (String newAssetPath : webViewContext.getApplicationInfo().getAllApkPaths()) {
+ initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath);
+ }
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 24f1fb5..4cb552d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -83,7 +83,7 @@
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
import android.widget.RemoteViews.OnClickHandler;
import com.android.internal.R;
@@ -1221,10 +1221,10 @@
* @return The current choice mode
*/
@InspectableProperty(enumMapping = {
- @EnumMap(value = CHOICE_MODE_NONE, name = "none"),
- @EnumMap(value = CHOICE_MODE_SINGLE, name = "singleChoice"),
- @EnumMap(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"),
- @EnumMap(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal")
+ @EnumEntry(value = CHOICE_MODE_NONE, name = "none"),
+ @EnumEntry(value = CHOICE_MODE_SINGLE, name = "singleChoice"),
+ @InspectableProperty.EnumEntry(value = CHOICE_MODE_MULTIPLE, name = "multipleChoice"),
+ @EnumEntry(value = CHOICE_MODE_MULTIPLE_MODAL, name = "multipleChoiceModal")
})
public int getChoiceMode() {
return mChoiceMode;
@@ -6293,9 +6293,9 @@
* {@link #TRANSCRIPT_MODE_ALWAYS_SCROLL}
*/
@InspectableProperty(enumMapping = {
- @EnumMap(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"),
- @EnumMap(value = TRANSCRIPT_MODE_NORMAL, name = "normal"),
- @EnumMap(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll")
+ @EnumEntry(value = TRANSCRIPT_MODE_DISABLED, name = "disabled"),
+ @EnumEntry(value = TRANSCRIPT_MODE_NORMAL, name = "normal"),
+ @EnumEntry(value = TRANSCRIPT_MODE_ALWAYS_SCROLL, name = "alwaysScroll")
})
public int getTranscriptMode() {
return mTranscriptMode;
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index ecb846b..0c593be 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -216,8 +216,8 @@
* @hide Visible for testing only.
*/
@InspectableProperty(name = "datePickerMode", enumMapping = {
- @InspectableProperty.EnumMap(value = MODE_SPINNER, name = "spinner"),
- @InspectableProperty.EnumMap(value = MODE_CALENDAR, name = "calendar")
+ @InspectableProperty.EnumEntry(value = MODE_SPINNER, name = "spinner"),
+ @InspectableProperty.EnumEntry(value = MODE_CALENDAR, name = "calendar")
})
@DatePickerMode
@TestApi
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b6ec5f9..c9ef038 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4984,9 +4984,6 @@
if (magnifierTopLeft == null) {
return;
}
- final Rect surfaceInsets =
- mTextView.getViewRootImpl().mWindowAttributes.surfaceInsets;
- magnifierTopLeft.offset(-surfaceInsets.left, -surfaceInsets.top);
final Rect magnifierRect = new Rect(magnifierTopLeft.x, magnifierTopLeft.y,
magnifierTopLeft.x + mMagnifierAnimator.mMagnifier.getWidth(),
magnifierTopLeft.y + mMagnifierAnimator.mMagnifier.getHeight());
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 1c8bb04..8cda47d 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -331,8 +331,8 @@
*/
@Orientation
@InspectableProperty(enumMapping = {
- @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
- @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
+ @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"),
+ @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical")
})
public int getOrientation() {
return mOrientation;
@@ -510,8 +510,8 @@
*/
@AlignmentMode
@InspectableProperty(enumMapping = {
- @InspectableProperty.EnumMap(value = ALIGN_BOUNDS, name = "alignBounds"),
- @InspectableProperty.EnumMap(value = ALIGN_MARGINS, name = "alignMargins"),
+ @InspectableProperty.EnumEntry(value = ALIGN_BOUNDS, name = "alignBounds"),
+ @InspectableProperty.EnumEntry(value = ALIGN_MARGINS, name = "alignMargins"),
})
public int getAlignmentMode() {
return mAlignmentMode;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f44c331..4e39a55 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2174,11 +2174,11 @@
@StretchMode
@InspectableProperty(enumMapping = {
- @InspectableProperty.EnumMap(value = NO_STRETCH, name = "none"),
- @InspectableProperty.EnumMap(value = STRETCH_SPACING, name = "spacingWidth"),
- @InspectableProperty.EnumMap(
+ @InspectableProperty.EnumEntry(value = NO_STRETCH, name = "none"),
+ @InspectableProperty.EnumEntry(value = STRETCH_SPACING, name = "spacingWidth"),
+ @InspectableProperty.EnumEntry(
value = STRETCH_SPACING_UNIFORM, name = "spacingWidthUniform"),
- @InspectableProperty.EnumMap(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"),
+ @InspectableProperty.EnumEntry(value = STRETCH_COLUMN_WIDTH, name = "columnWidth"),
})
public int getStretchMode() {
return mStretchMode;
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index bdde435..a83e826 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1850,8 +1850,8 @@
*/
@OrientationMode
@InspectableProperty(enumMapping = {
- @InspectableProperty.EnumMap(value = HORIZONTAL, name = "horizontal"),
- @InspectableProperty.EnumMap(value = VERTICAL, name = "vertical")
+ @InspectableProperty.EnumEntry(value = HORIZONTAL, name = "horizontal"),
+ @InspectableProperty.EnumEntry(value = VERTICAL, name = "vertical")
})
public int getOrientation() {
return mOrientation;
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 50e8836..08799cf 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -471,13 +471,13 @@
}
/**
- * Returns the top left coordinates of the magnifier, relative to the surface of the
- * main application window. They will be determined by the coordinates of the last
- * {@link #show(float, float)} or {@link #show(float, float, float, float)} call, adjusted
- * to take into account any potential clamping behavior. The method can be used immediately
- * after a #show call to find out where the magnifier will be positioned. However, the
- * position of the magnifier will not be updated in the same frame due to the async
- * copying of the content copying and of the magnifier rendering.
+ * Returns the top left coordinates of the magnifier, relative to the main application
+ * window. They will be determined by the coordinates of the last {@link #show(float, float)}
+ * or {@link #show(float, float, float, float)} call, adjusted to take into account any
+ * potential clamping behavior. The method can be used immediately after a #show
+ * call to find out where the magnifier will be positioned. However, the position of the
+ * magnifier will not be updated visually in the same frame, due to the async nature of
+ * the content copying and of the magnifier rendering.
* The method will return {@code null} if #show has not yet been called, or if the last
* operation performed was a #dismiss.
*
@@ -488,15 +488,18 @@
if (mWindow == null) {
return null;
}
- return new Point(getCurrentClampedWindowCoordinates());
+ final Point position = getCurrentClampedWindowCoordinates();
+ position.offset(-mParentSurface.mInsets.left, -mParentSurface.mInsets.top);
+ return new Point(position);
}
/**
* Returns the top left coordinates of the magnifier source (i.e. the view region going to
- * be magnified and copied to the magnifier), relative to the surface the content is copied
- * from. The content will be copied:
+ * be magnified and copied to the magnifier), relative to the window or surface the content
+ * is copied from. The content will be copied:
* - if the magnified view is a {@link SurfaceView}, from the surface backing it
- * - otherwise, from the surface of the main application window
+ * - otherwise, from the surface backing the main application window, and the coordinates
+ * returned will be relative to the main application window
* The method will return {@code null} if #show has not yet been called, or if the last
* operation performed was a #dismiss.
*
@@ -507,7 +510,9 @@
if (mWindow == null) {
return null;
}
- return new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top);
+ final Point position = new Point(mPixelCopyRequestRect.left, mPixelCopyRequestRect.top);
+ position.offset(-mContentCopySurface.mInsets.left, -mContentCopySurface.mInsets.top);
+ return new Point(position);
}
/**
@@ -531,7 +536,7 @@
viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom;
validMainWindowSurface =
new SurfaceInfo(viewRootImpl.getSurfaceControl(), mainWindowSurface,
- surfaceWidth, surfaceHeight, true);
+ surfaceWidth, surfaceHeight, surfaceInsets, true);
}
}
// Get the surface backing the magnified view, if it is a SurfaceView.
@@ -544,7 +549,7 @@
if (sc != null && sc.isValid()) {
final Rect surfaceFrame = surfaceHolder.getSurfaceFrame();
validSurfaceViewSurface = new SurfaceInfo(sc, surfaceViewSurface,
- surfaceFrame.right, surfaceFrame.bottom, false);
+ surfaceFrame.right, surfaceFrame.bottom, new Rect(), false);
}
}
@@ -708,9 +713,13 @@
final Rect windowBounds;
if (mParentSurface.mIsMainWindowSurface) {
final Insets systemInsets = mView.getRootWindowInsets().getSystemWindowInsets();
- windowBounds = new Rect(systemInsets.left, systemInsets.top,
- mParentSurface.mWidth - systemInsets.right,
- mParentSurface.mHeight - systemInsets.bottom);
+ windowBounds = new Rect(
+ systemInsets.left + mParentSurface.mInsets.left,
+ systemInsets.top + mParentSurface.mInsets.top,
+ mParentSurface.mWidth - systemInsets.right - mParentSurface.mInsets.right,
+ mParentSurface.mHeight - systemInsets.bottom
+ - mParentSurface.mInsets.bottom
+ );
} else {
windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight);
}
@@ -725,21 +734,23 @@
* Contains a surface and metadata corresponding to it.
*/
private static class SurfaceInfo {
- public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, false);
+ public static final SurfaceInfo NULL = new SurfaceInfo(null, null, 0, 0, null, false);
private Surface mSurface;
private SurfaceControl mSurfaceControl;
private int mWidth;
private int mHeight;
+ private Rect mInsets;
private boolean mIsMainWindowSurface;
SurfaceInfo(final SurfaceControl surfaceControl, final Surface surface,
- final int width, final int height,
+ final int width, final int height, final Rect insets,
final boolean isMainWindowSurface) {
mSurfaceControl = surfaceControl;
mSurface = surface;
mWidth = width;
mHeight = height;
+ mInsets = insets;
mIsMainWindowSurface = isMainWindowSurface;
}
}
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
new file mode 100644
index 0000000..ee378ff
--- /dev/null
+++ b/core/java/android/widget/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsWidgetTestCases",
+ "options": [
+ {
+ "instrumentation-arg": "size:=small"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 04bcb14..a5a1a80c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -173,8 +173,8 @@
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.view.inspector.InspectableProperty;
-import android.view.inspector.InspectableProperty.EnumMap;
-import android.view.inspector.InspectableProperty.FlagMap;
+import android.view.inspector.InspectableProperty.EnumEntry;
+import android.view.inspector.InspectableProperty.FlagEntry;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
@@ -1900,8 +1900,8 @@
* @see #setAutoSizeTextTypeUniformWithPresetSizes(int[], int)
*/
@InspectableProperty(enumMapping = {
- @EnumMap(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE),
- @EnumMap(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM)
+ @EnumEntry(name = "none", value = AUTO_SIZE_TEXT_TYPE_NONE),
+ @EnumEntry(name = "uniform", value = AUTO_SIZE_TEXT_TYPE_UNIFORM)
})
@AutoSizeTextType
public int getAutoSizeTextType() {
@@ -3527,10 +3527,10 @@
* @attr ref android.R.styleable#TextView_autoLink
*/
@InspectableProperty(name = "autoLink", flagMapping = {
- @FlagMap(name = "web", target = Linkify.WEB_URLS),
- @FlagMap(name = "email", target = Linkify.EMAIL_ADDRESSES),
- @FlagMap(name = "phone", target = Linkify.PHONE_NUMBERS),
- @FlagMap(name = "map", target = Linkify.MAP_ADDRESSES)
+ @FlagEntry(name = "web", target = Linkify.WEB_URLS),
+ @FlagEntry(name = "email", target = Linkify.EMAIL_ADDRESSES),
+ @FlagEntry(name = "phone", target = Linkify.PHONE_NUMBERS),
+ @FlagEntry(name = "map", target = Linkify.MAP_ADDRESSES)
})
public final int getAutoLinkMask() {
return mAutoLinkMask;
@@ -4515,9 +4515,9 @@
* @see #setBreakStrategy(int)
*/
@InspectableProperty(enumMapping = {
- @EnumMap(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE),
- @EnumMap(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY),
- @EnumMap(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED)
+ @EnumEntry(name = "simple", value = Layout.BREAK_STRATEGY_SIMPLE),
+ @EnumEntry(name = "high_quality", value = Layout.BREAK_STRATEGY_HIGH_QUALITY),
+ @EnumEntry(name = "balanced", value = Layout.BREAK_STRATEGY_BALANCED)
})
@Layout.BreakStrategy
public int getBreakStrategy() {
@@ -4566,9 +4566,9 @@
* @see #setHyphenationFrequency(int)
*/
@InspectableProperty(enumMapping = {
- @EnumMap(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE),
- @EnumMap(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL),
- @EnumMap(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL)
+ @EnumEntry(name = "none", value = Layout.HYPHENATION_FREQUENCY_NONE),
+ @EnumEntry(name = "normal", value = Layout.HYPHENATION_FREQUENCY_NORMAL),
+ @EnumEntry(name = "full", value = Layout.HYPHENATION_FREQUENCY_FULL)
})
@Layout.HyphenationFrequency
public int getHyphenationFrequency() {
@@ -4628,8 +4628,8 @@
* @see #setJustificationMode(int)
*/
@InspectableProperty(enumMapping = {
- @EnumMap(name = "none", value = Layout.JUSTIFICATION_MODE_NONE),
- @EnumMap(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD)
+ @EnumEntry(name = "none", value = Layout.JUSTIFICATION_MODE_NONE),
+ @EnumEntry(name = "inter_word", value = Layout.JUSTIFICATION_MODE_INTER_WORD)
})
public @Layout.JustificationMode int getJustificationMode() {
return mJustificationMode;
@@ -6667,142 +6667,142 @@
* @see android.text.InputType
*/
@InspectableProperty(flagMapping = {
- @FlagMap(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL),
- @FlagMap(
+ @FlagEntry(name = "none", mask = 0xffffffff, target = InputType.TYPE_NULL),
+ @FlagEntry(
name = "text",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL),
- @FlagMap(
+ @FlagEntry(
name = "textUri",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI),
- @FlagMap(
+ @FlagEntry(
name = "textEmailAddress",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS),
- @FlagMap(
+ @FlagEntry(
name = "textEmailSubject",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT),
- @FlagMap(
+ @FlagEntry(
name = "textShortMessage",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE),
- @FlagMap(
+ @FlagEntry(
name = "textLongMessage",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE),
- @FlagMap(
+ @FlagEntry(
name = "textPersonName",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_PERSON_NAME),
- @FlagMap(
+ @FlagEntry(
name = "textPostalAddress",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS),
- @FlagMap(
+ @FlagEntry(
name = "textPassword",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD),
- @FlagMap(
+ @FlagEntry(
name = "textVisiblePassword",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD),
- @FlagMap(
+ @FlagEntry(
name = "textWebEditText",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT),
- @FlagMap(
+ @FlagEntry(
name = "textFilter",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_FILTER),
- @FlagMap(
+ @FlagEntry(
name = "textPhonetic",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PHONETIC),
- @FlagMap(
+ @FlagEntry(
name = "textWebEmailAddress",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS),
- @FlagMap(
+ @FlagEntry(
name = "textWebPassword",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD),
- @FlagMap(
+ @FlagEntry(
name = "number",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_NORMAL),
- @FlagMap(
+ @FlagEntry(
name = "numberPassword",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_NUMBER
| InputType.TYPE_NUMBER_VARIATION_PASSWORD),
- @FlagMap(
+ @FlagEntry(
name = "phone",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_PHONE),
- @FlagMap(
+ @FlagEntry(
name = "datetime",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_NORMAL),
- @FlagMap(
+ @FlagEntry(
name = "date",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_DATE),
- @FlagMap(
+ @FlagEntry(
name = "time",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION,
target = InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_TIME),
- @FlagMap(
+ @FlagEntry(
name = "textCapCharacters",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS),
- @FlagMap(
+ @FlagEntry(
name = "textCapWords",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_WORDS),
- @FlagMap(
+ @FlagEntry(
name = "textCapSentences",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES),
- @FlagMap(
+ @FlagEntry(
name = "textAutoCorrect",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT),
- @FlagMap(
+ @FlagEntry(
name = "textAutoComplete",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE),
- @FlagMap(
+ @FlagEntry(
name = "textMultiLine",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE),
- @FlagMap(
+ @FlagEntry(
name = "textImeMultiLine",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE),
- @FlagMap(
+ @FlagEntry(
name = "textNoSuggestions",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS),
- @FlagMap(
+ @FlagEntry(
name = "numberSigned",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED),
- @FlagMap(
+ @FlagEntry(
name = "numberDecimal",
mask = InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_FLAGS,
target = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL),
@@ -6832,49 +6832,51 @@
* @see EditorInfo
*/
@InspectableProperty(flagMapping = {
- @FlagMap(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL),
- @FlagMap(
+ @FlagEntry(name = "normal", mask = 0xffffffff, target = EditorInfo.IME_NULL),
+ @FlagEntry(
name = "actionUnspecified",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_UNSPECIFIED),
- @FlagMap(
+ @FlagEntry(
name = "actionNone",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_NONE),
- @FlagMap(
+ @FlagEntry(
name = "actionGo",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_GO),
- @FlagMap(
+ @FlagEntry(
name = "actionSearch",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_SEARCH),
- @FlagMap(
+ @FlagEntry(
name = "actionSend",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_SEND),
- @FlagMap(
+ @FlagEntry(
name = "actionNext",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_NEXT),
- @FlagMap(
+ @FlagEntry(
name = "actionDone",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_DONE),
- @FlagMap(
+ @FlagEntry(
name = "actionPrevious",
mask = EditorInfo.IME_MASK_ACTION,
target = EditorInfo.IME_ACTION_PREVIOUS),
- @FlagMap(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII),
- @FlagMap(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT),
- @FlagMap(name = "flagNavigatePrevious", target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS),
- @FlagMap(
+ @FlagEntry(name = "flagForceAscii", target = EditorInfo.IME_FLAG_FORCE_ASCII),
+ @FlagEntry(name = "flagNavigateNext", target = EditorInfo.IME_FLAG_NAVIGATE_NEXT),
+ @FlagEntry(
+ name = "flagNavigatePrevious",
+ target = EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS),
+ @FlagEntry(
name = "flagNoAccessoryAction",
target = EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION),
- @FlagMap(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION),
- @FlagMap(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI),
- @FlagMap(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN),
- @FlagMap(
+ @FlagEntry(name = "flagNoEnterAction", target = EditorInfo.IME_FLAG_NO_ENTER_ACTION),
+ @FlagEntry(name = "flagNoExtractUi", target = EditorInfo.IME_FLAG_NO_EXTRACT_UI),
+ @FlagEntry(name = "flagNoFullscreen", target = EditorInfo.IME_FLAG_NO_FULLSCREEN),
+ @FlagEntry(
name = "flagNoPersonalizedLearning",
target = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING),
})
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index c7a2980..8a5d531 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -169,8 +169,8 @@
@TimePickerMode
@TestApi
@InspectableProperty(name = "timePickerMode", enumMapping = {
- @InspectableProperty.EnumMap(name = "clock", value = MODE_CLOCK),
- @InspectableProperty.EnumMap(name = "spinner", value = MODE_SPINNER)
+ @InspectableProperty.EnumEntry(name = "clock", value = MODE_CLOCK),
+ @InspectableProperty.EnumEntry(name = "spinner", value = MODE_SPINNER)
})
public int getMode() {
return mMode;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index f250666..faf0c7d 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -680,7 +680,7 @@
& DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
}
}
- } catch (SecurityException e) {
+ } catch (SecurityException | NullPointerException e) {
Log.w(TAG, "Error loading file preview", e);
}
@@ -918,6 +918,8 @@
if (isSendAction(in)) {
in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+
+ in.fixUris(getUserId());
}
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index c4af4c7..1c90182 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -79,4 +79,6 @@
void stopWatchingNoted(IAppOpsNotedCallback callback);
int checkOperationRaw(int code, int uid, String packageName);
+
+ void reloadNonHistoricalState();
}
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index f8117a7..c9baf00 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -79,14 +79,14 @@
Intent dataManagementIntent();
/**
- * On demand, supply a short string that can be shown to the user as the label
- * on an overflow menu item used to invoked the data management UI.
+ * On demand, supply a short {@link CharSequence} that can be shown to the user as the label on
+ * an overflow menu item used to invoke the data management UI.
*
- * @return A string to be used as the label for the transport's data management
+ * @return A {@link CharSequence} to be used as the label for the transport's data management
* affordance. If the transport supplies a data management intent, this
* method must not return {@code null}.
*/
- String dataManagementLabel();
+ CharSequence dataManagementIntentLabel();
/**
* Ask the transport where, on local device storage, to keep backup state blobs.
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index eb881de..5c144d3 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -577,6 +577,12 @@
protected boolean isFinal() {
return false;
}
+
+ protected boolean isRequestCompleted() {
+ synchronized (mLock) {
+ return mCompleted;
+ }
+ }
}
/**
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index ead98e7..e85508e 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -368,6 +368,11 @@
public void refreshStats(int statsType, SparseArray<UserHandle> asUsers, long rawRealtimeUs,
long rawUptimeUs) {
+ if (statsType != BatteryStats.STATS_SINCE_CHARGED) {
+ Log.w(TAG, "refreshStats called for statsType " + statsType + " but only "
+ + "STATS_SINCE_CHARGED is supported. Using STATS_SINCE_CHARGED instead.");
+ }
+
// Initialize mStats if necessary.
getStats();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8679dcb..1fc7635 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -145,7 +145,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 185 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0);
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -991,8 +991,6 @@
private int mPhoneSimStateRaw = -1;
private int mNumConnectivityChange;
- private int mLoadedNumConnectivityChange;
- private int mUnpluggedNumConnectivityChange;
private int mEstimatedBatteryCapacity = -1;
@@ -1225,27 +1223,11 @@
}
public long computeUptime(long curTime, int which) {
- switch (which) {
- case STATS_SINCE_CHARGED:
- return mUptime + getUptime(curTime);
- case STATS_CURRENT:
- return getUptime(curTime);
- case STATS_SINCE_UNPLUGGED:
- return getUptime(curTime) - mUnpluggedUptime;
- }
- return 0;
+ return mUptime + getUptime(curTime);
}
public long computeRealtime(long curTime, int which) {
- switch (which) {
- case STATS_SINCE_CHARGED:
- return mRealtime + getRealtime(curTime);
- case STATS_CURRENT:
- return getRealtime(curTime);
- case STATS_SINCE_UNPLUGGED:
- return getRealtime(curTime) - mUnpluggedRealtime;
- }
- return 0;
+ return mRealtime + getRealtime(curTime);
}
public long getUptime(long curTime) {
@@ -1352,16 +1334,10 @@
@UnsupportedAppUsage
final AtomicInteger mCount = new AtomicInteger();
final TimeBase mTimeBase;
- int mLoadedCount;
- int mUnpluggedCount;
- int mPluggedCount;
public Counter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
- mPluggedCount = in.readInt();
- mCount.set(mPluggedCount);
- mLoadedCount = in.readInt();
- mUnpluggedCount = in.readInt();
+ mCount.set(in.readInt());
timeBase.add(this);
}
@@ -1372,18 +1348,14 @@
public void writeToParcel(Parcel out) {
out.writeInt(mCount.get());
- out.writeInt(mLoadedCount);
- out.writeInt(mUnpluggedCount);
}
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedCount = mPluggedCount;
}
@Override
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mPluggedCount = mCount.get();
}
/**
@@ -1417,21 +1389,11 @@
@Override
public int getCountLocked(int which) {
- int val = mCount.get();
- if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedCount;
- } else if (which != STATS_SINCE_CHARGED) {
- val -= mLoadedCount;
- }
-
- return val;
+ return mCount.get();
}
public void logState(Printer pw, String prefix) {
- pw.println(prefix + "mCount=" + mCount.get()
- + " mLoadedCount=" + mLoadedCount
- + " mUnpluggedCount=" + mUnpluggedCount
- + " mPluggedCount=" + mPluggedCount);
+ pw.println(prefix + "mCount=" + mCount.get());
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -1453,7 +1415,6 @@
@Override
public boolean reset(boolean detachIfReset) {
mCount.set(0);
- mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
@@ -1467,15 +1428,12 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public void writeSummaryFromParcelLocked(Parcel out) {
- int count = mCount.get();
- out.writeInt(count);
+ out.writeInt(mCount.get());
}
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public void readSummaryFromParcelLocked(Parcel in) {
- mLoadedCount = in.readInt();
- mCount.set(mLoadedCount);
- mUnpluggedCount = mPluggedCount = mLoadedCount;
+ mCount.set(in.readInt());
}
}
@@ -1483,14 +1441,10 @@
public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs {
final TimeBase mTimeBase;
public long[] mCounts;
- public long[] mLoadedCounts;
- public long[] mUnpluggedCounts;
private LongSamplingCounterArray(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
mCounts = in.createLongArray();
- mLoadedCounts = in.createLongArray();
- mUnpluggedCounts = in.createLongArray();
timeBase.add(this);
}
@@ -1501,13 +1455,10 @@
private void writeToParcel(Parcel out) {
out.writeLongArray(mCounts);
- out.writeLongArray(mLoadedCounts);
- out.writeLongArray(mUnpluggedCounts);
}
@Override
public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) {
- mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
}
@Override
@@ -1516,20 +1467,12 @@
@Override
public long[] getCountsLocked(int which) {
- long[] val = copyArray(mCounts, null);
- if (which == STATS_SINCE_UNPLUGGED) {
- subtract(val, mUnpluggedCounts);
- } else if (which != STATS_SINCE_CHARGED) {
- subtract(val, mLoadedCounts);
- }
- return val;
+ return mCounts == null ? null : Arrays.copyOf(mCounts, mCounts.length);
}
@Override
public void logState(Printer pw, String prefix) {
- pw.println(prefix + "mCounts=" + Arrays.toString(mCounts)
- + " mLoadedCounts=" + Arrays.toString(mLoadedCounts)
- + " mUnpluggedCounts=" + Arrays.toString(mUnpluggedCounts));
+ pw.println(prefix + "mCounts=" + Arrays.toString(mCounts));
}
public void addCountLocked(long[] counts) {
@@ -1559,9 +1502,9 @@
*/
@Override
public boolean reset(boolean detachIfReset) {
- fillArray(mCounts, 0);
- fillArray(mLoadedCounts, 0);
- fillArray(mUnpluggedCounts, 0);
+ if (mCounts != null) {
+ Arrays.fill(mCounts, 0);
+ }
if (detachIfReset) {
detach();
}
@@ -1579,8 +1522,6 @@
private void readSummaryFromParcelLocked(Parcel in) {
mCounts = in.createLongArray();
- mLoadedCounts = copyArray(mCounts, mLoadedCounts);
- mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts);
}
public static void writeToParcel(Parcel out, LongSamplingCounterArray counterArray) {
@@ -1621,49 +1562,16 @@
return null;
}
}
-
- private static void fillArray(long[] a, long val) {
- if (a != null) {
- Arrays.fill(a, val);
- }
- }
-
- private static void subtract(@NonNull long[] val, long[] toSubtract) {
- if (toSubtract == null) {
- return;
- }
- for (int i = 0; i < val.length; i++) {
- val[i] -= toSubtract[i];
- }
- }
-
- private static long[] copyArray(long[] src, long[] dest) {
- if (src == null) {
- return null;
- } else {
- if (dest == null) {
- dest = new long[src.length];
- }
- System.arraycopy(src, 0, dest, 0, src.length);
- return dest;
- }
- }
}
@VisibleForTesting
public static class LongSamplingCounter extends LongCounter implements TimeBaseObs {
final TimeBase mTimeBase;
- public long mCount;
- public long mCurrentCount;
- public long mLoadedCount;
- public long mUnpluggedCount;
+ private long mCount;
public LongSamplingCounter(TimeBase timeBase, Parcel in) {
mTimeBase = timeBase;
mCount = in.readLong();
- mCurrentCount = in.readLong();
- mLoadedCount = in.readLong();
- mUnpluggedCount = in.readLong();
timeBase.add(this);
}
@@ -1674,14 +1582,10 @@
public void writeToParcel(Parcel out) {
out.writeLong(mCount);
- out.writeLong(mCurrentCount);
- out.writeLong(mLoadedCount);
- out.writeLong(mUnpluggedCount);
}
@Override
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedCount = mCount;
}
@Override
@@ -1689,43 +1593,22 @@
}
public long getCountLocked(int which) {
- long val = mCount;
- if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedCount;
- } else if (which != STATS_SINCE_CHARGED) {
- val -= mLoadedCount;
- }
- return val;
+ return mCount;
}
@Override
public void logState(Printer pw, String prefix) {
- pw.println(prefix + "mCount=" + mCount
- + " mCurrentCount=" + mCurrentCount
- + " mLoadedCount=" + mLoadedCount
- + " mUnpluggedCount=" + mUnpluggedCount);
+ pw.println(prefix + "mCount=" + mCount);
}
public void addCountLocked(long count) {
- update(mCurrentCount + count, mTimeBase.isRunning());
+ addCountLocked(count, mTimeBase.isRunning());
}
public void addCountLocked(long count, boolean isRunning) {
- update(mCurrentCount + count, isRunning);
- }
-
- public void update(long count) {
- update(count, mTimeBase.isRunning());
- }
-
- public void update(long count, boolean isRunning) {
- if (count < mCurrentCount) {
- mCurrentCount = 0;
- }
if (isRunning) {
- mCount += count - mCurrentCount;
+ mCount += count;
}
- mCurrentCount = count;
}
/**
@@ -1734,7 +1617,6 @@
@Override
public boolean reset(boolean detachIfReset) {
mCount = 0;
- mLoadedCount = mUnpluggedCount = 0;
if (detachIfReset) {
detach();
}
@@ -1751,7 +1633,7 @@
}
public void readSummaryFromParcelLocked(Parcel in) {
- mCount = mUnpluggedCount= mLoadedCount = in.readLong();
+ mCount = in.readLong();
}
}
@@ -1764,9 +1646,6 @@
protected final TimeBase mTimeBase;
protected int mCount;
- protected int mLoadedCount;
- protected int mLastCount;
- protected int mUnpluggedCount;
// Times are in microseconds for better accuracy when dividing by the
// lock count, and are in "battery realtime" units.
@@ -1779,25 +1658,6 @@
protected long mTotalTime;
/**
- * The total time we loaded for the previous runs. Subtract this from
- * mTotalTime to find the time for the current run of the system.
- */
- protected long mLoadedTime;
-
- /**
- * The run time of the last run of the system, as loaded from the
- * saved data.
- */
- protected long mLastTime;
-
- /**
- * The value of mTotalTime when unplug() was last called. Subtract
- * this from mTotalTime to find the time since the last unplug from
- * power.
- */
- protected long mUnpluggedTime;
-
- /**
* The total time this timer has been running until the latest mark has been set.
* Subtract this from mTotalTime to get the time spent running since the mark was set.
*/
@@ -1815,13 +1675,7 @@
mTimeBase = timeBase;
mCount = in.readInt();
- mLoadedCount = in.readInt();
- mLastCount = 0;
- mUnpluggedCount = in.readInt();
mTotalTime = in.readLong();
- mLoadedTime = in.readLong();
- mLastTime = 0;
- mUnpluggedTime = in.readLong();
mTimeBeforeMark = in.readLong();
timeBase.add(this);
if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
@@ -1834,6 +1688,16 @@
timeBase.add(this);
}
+ public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
+ if (DEBUG) {
+ Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime="
+ + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
+ }
+ out.writeInt(computeCurrentCountLocked());
+ out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
+ out.writeLong(mTimeBeforeMark);
+ }
+
protected abstract long computeRunTimeLocked(long curBatteryRealtime);
protected abstract int computeCurrentCountLocked();
@@ -1844,8 +1708,8 @@
*/
@Override
public boolean reset(boolean detachIfReset) {
- mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0;
- mCount = mLoadedCount = mLastCount = 0;
+ mTotalTime = mTimeBeforeMark = 0;
+ mCount = 0;
if (detachIfReset) {
detach();
}
@@ -1857,32 +1721,8 @@
mTimeBase.remove(this);
}
- public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
- if (DEBUG) Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime="
- + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
- out.writeInt(computeCurrentCountLocked());
- out.writeInt(mLoadedCount);
- out.writeInt(mUnpluggedCount);
- out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
- out.writeLong(mLoadedTime);
- out.writeLong(mUnpluggedTime);
- out.writeLong(mTimeBeforeMark);
- }
-
@Override
public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) {
- if (DEBUG && mType < 0) {
- Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime
- + " old mUnpluggedTime=" + mUnpluggedTime
- + " old mUnpluggedCount=" + mUnpluggedCount);
- }
- mUnpluggedTime = computeRunTimeLocked(baseRealtime);
- mUnpluggedCount = computeCurrentCountLocked();
- if (DEBUG && mType < 0) {
- Log.v(TAG, "unplug #" + mType
- + ": new mUnpluggedTime=" + mUnpluggedTime
- + " new mUnpluggedCount=" + mUnpluggedCount);
- }
}
@Override
@@ -1894,8 +1734,7 @@
mTotalTime = computeRunTimeLocked(baseRealtime);
mCount = computeCurrentCountLocked();
if (DEBUG && mType < 0) {
- Log.v(TAG, "plug #" + mType
- + ": new mTotalTime=" + mTotalTime);
+ Log.v(TAG, "plug #" + mType + ": new mTotalTime=" + mTotalTime);
}
}
@@ -1912,34 +1751,19 @@
return;
}
out.writeInt(1); // indicates non-null
-
timer.writeToParcel(out, elapsedRealtimeUs);
}
@Override
@UnsupportedAppUsage
public long getTotalTimeLocked(long elapsedRealtimeUs, int which) {
- long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
- if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedTime;
- } else if (which != STATS_SINCE_CHARGED) {
- val -= mLoadedTime;
- }
-
- return val;
+ return computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
}
@Override
@UnsupportedAppUsage
public int getCountLocked(int which) {
- int val = computeCurrentCountLocked();
- if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedCount;
- } else if (which != STATS_SINCE_CHARGED) {
- val -= mLoadedCount;
- }
-
- return val;
+ return computeCurrentCountLocked();
}
@Override
@@ -1950,13 +1774,8 @@
@Override
public void logState(Printer pw, String prefix) {
- pw.println(prefix + "mCount=" + mCount
- + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
- + " mUnpluggedCount=" + mUnpluggedCount);
- pw.println(prefix + "mTotalTime=" + mTotalTime
- + " mLoadedTime=" + mLoadedTime);
- pw.println(prefix + "mLastTime=" + mLastTime
- + " mUnpluggedTime=" + mUnpluggedTime);
+ pw.println(prefix + "mCount=" + mCount);
+ pw.println(prefix + "mTotalTime=" + mTotalTime);
}
@@ -1968,13 +1787,8 @@
public void readSummaryFromParcelLocked(Parcel in) {
// Multiply by 1000 for backwards compatibility
- mTotalTime = mLoadedTime = in.readLong();
- mLastTime = 0;
- mUnpluggedTime = mTotalTime;
- mCount = mLoadedCount = in.readInt();
- mLastCount = 0;
- mUnpluggedCount = mCount;
-
+ mTotalTime = in.readLong();
+ mCount = in.readInt();
// When reading the summary, we set the mark to be the latest information.
mTimeBeforeMark = mTotalTime;
}
@@ -2233,7 +2047,7 @@
private long computeOverage(long curTime) {
if (mLastAddedTime > 0) {
- return mLastTime + mLastAddedDuration - curTime;
+ return mLastAddedDuration - curTime;
}
return 0;
}
@@ -2452,7 +2266,7 @@
mTotalDurationMs = 0;
mCurrentDurationMs = 0;
if (mNesting > 0) {
- mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000;
+ mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000) / 1000;
} else {
mStartTimeMs = -1;
}
@@ -2491,7 +2305,7 @@
public long getCurrentDurationMsLocked(long elapsedRealtimeMs) {
long durationMs = mCurrentDurationMs;
if (mNesting > 0 && mTimeBase.isRunning()) {
- durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000)
+ durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs * 1000) / 1000)
- mStartTimeMs;
}
return durationMs;
@@ -6401,13 +6215,7 @@
}
@Override public int getNumConnectivityChange(int which) {
- int val = mNumConnectivityChange;
- if (which == STATS_CURRENT) {
- val -= mLoadedNumConnectivityChange;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedNumConnectivityChange;
- }
- return val;
+ return mNumConnectivityChange;
}
@Override public long getGpsSignalQualityTime(int strengthBin,
@@ -9122,66 +8930,6 @@
*/
int mNumAnrs;
- /**
- * The amount of user time loaded from a previous save.
- */
- long mLoadedUserTime;
-
- /**
- * The amount of system time loaded from a previous save.
- */
- long mLoadedSystemTime;
-
- /**
- * The amount of foreground time loaded from a previous save.
- */
- long mLoadedForegroundTime;
-
- /**
- * The number of times the process has started from a previous save.
- */
- int mLoadedStarts;
-
- /**
- * Number of times the process has crashed from a previous save.
- */
- int mLoadedNumCrashes;
-
- /**
- * Number of times the process has had an ANR from a previous save.
- */
- int mLoadedNumAnrs;
-
- /**
- * The amount of user time when last unplugged.
- */
- long mUnpluggedUserTime;
-
- /**
- * The amount of system time when last unplugged.
- */
- long mUnpluggedSystemTime;
-
- /**
- * The amount of foreground time since unplugged.
- */
- long mUnpluggedForegroundTime;
-
- /**
- * The number of times the process has started before unplugged.
- */
- int mUnpluggedStarts;
-
- /**
- * Number of times the process has crashed before unplugged.
- */
- int mUnpluggedNumCrashes;
-
- /**
- * Number of times the process has had an ANR before unplugged.
- */
- int mUnpluggedNumAnrs;
-
ArrayList<ExcessivePower> mExcessivePower;
public Proc(BatteryStatsImpl bsi, String name) {
@@ -9191,12 +8939,6 @@
}
public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
- mUnpluggedUserTime = mUserTime;
- mUnpluggedSystemTime = mSystemTime;
- mUnpluggedForegroundTime = mForegroundTime;
- mUnpluggedStarts = mStarts;
- mUnpluggedNumCrashes = mNumCrashes;
- mUnpluggedNumAnrs = mNumAnrs;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -9283,18 +9025,6 @@
out.writeInt(mStarts);
out.writeInt(mNumCrashes);
out.writeInt(mNumAnrs);
- out.writeLong(mLoadedUserTime);
- out.writeLong(mLoadedSystemTime);
- out.writeLong(mLoadedForegroundTime);
- out.writeInt(mLoadedStarts);
- out.writeInt(mLoadedNumCrashes);
- out.writeInt(mLoadedNumAnrs);
- out.writeLong(mUnpluggedUserTime);
- out.writeLong(mUnpluggedSystemTime);
- out.writeLong(mUnpluggedForegroundTime);
- out.writeInt(mUnpluggedStarts);
- out.writeInt(mUnpluggedNumCrashes);
- out.writeInt(mUnpluggedNumAnrs);
writeExcessivePowerToParcelLocked(out);
}
@@ -9305,18 +9035,6 @@
mStarts = in.readInt();
mNumCrashes = in.readInt();
mNumAnrs = in.readInt();
- mLoadedUserTime = in.readLong();
- mLoadedSystemTime = in.readLong();
- mLoadedForegroundTime = in.readLong();
- mLoadedStarts = in.readInt();
- mLoadedNumCrashes = in.readInt();
- mLoadedNumAnrs = in.readInt();
- mUnpluggedUserTime = in.readLong();
- mUnpluggedSystemTime = in.readLong();
- mUnpluggedForegroundTime = in.readLong();
- mUnpluggedStarts = in.readInt();
- mUnpluggedNumCrashes = in.readInt();
- mUnpluggedNumAnrs = in.readInt();
readExcessivePowerFromParcelLocked(in);
}
@@ -9358,71 +9076,35 @@
@Override
@UnsupportedAppUsage
public long getUserTime(int which) {
- long val = mUserTime;
- if (which == STATS_CURRENT) {
- val -= mLoadedUserTime;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedUserTime;
- }
- return val;
+ return mUserTime;
}
@Override
@UnsupportedAppUsage
public long getSystemTime(int which) {
- long val = mSystemTime;
- if (which == STATS_CURRENT) {
- val -= mLoadedSystemTime;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedSystemTime;
- }
- return val;
+ return mSystemTime;
}
@Override
@UnsupportedAppUsage
public long getForegroundTime(int which) {
- long val = mForegroundTime;
- if (which == STATS_CURRENT) {
- val -= mLoadedForegroundTime;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedForegroundTime;
- }
- return val;
+ return mForegroundTime;
}
@Override
@UnsupportedAppUsage
public int getStarts(int which) {
- int val = mStarts;
- if (which == STATS_CURRENT) {
- val -= mLoadedStarts;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedStarts;
- }
- return val;
+ return mStarts;
}
@Override
public int getNumCrashes(int which) {
- int val = mNumCrashes;
- if (which == STATS_CURRENT) {
- val -= mLoadedNumCrashes;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedNumCrashes;
- }
- return val;
+ return mNumCrashes;
}
@Override
public int getNumAnrs(int which) {
- int val = mNumAnrs;
- if (which == STATS_CURRENT) {
- val -= mLoadedNumAnrs;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedNumAnrs;
- }
- return val;
+ return mNumAnrs;
}
}
@@ -9588,54 +9270,6 @@
protected int mLaunches;
/**
- * The amount of time spent started loaded from a previous save
- * (ms in battery uptime).
- */
- protected long mLoadedStartTime;
-
- /**
- * The number of starts loaded from a previous save.
- */
- protected int mLoadedStarts;
-
- /**
- * The number of launches loaded from a previous save.
- */
- protected int mLoadedLaunches;
-
- /**
- * The amount of time spent started as of the last run (ms
- * in battery uptime).
- */
- protected long mLastStartTime;
-
- /**
- * The number of starts as of the last run.
- */
- protected int mLastStarts;
-
- /**
- * The number of launches as of the last run.
- */
- protected int mLastLaunches;
-
- /**
- * The amount of time spent started when last unplugged (ms
- * in battery uptime).
- */
- protected long mUnpluggedStartTime;
-
- /**
- * The number of starts when last unplugged.
- */
- protected int mUnpluggedStarts;
-
- /**
- * The number of launches when last unplugged.
- */
- protected int mUnpluggedLaunches;
-
- /**
* Construct a Serv. Also adds it to the on-battery time base as a listener.
*/
public Serv(BatteryStatsImpl bsi) {
@@ -9645,9 +9279,6 @@
public void onTimeStarted(long elapsedRealtime, long baseUptime,
long baseRealtime) {
- mUnpluggedStartTime = getStartTimeToNowLocked(baseUptime);
- mUnpluggedStarts = mStarts;
- mUnpluggedLaunches = mLaunches;
}
public void onTimeStopped(long elapsedRealtime, long baseUptime,
@@ -9679,15 +9310,6 @@
mLaunchedSince = in.readLong();
mLaunched = in.readInt() != 0;
mLaunches = in.readInt();
- mLoadedStartTime = in.readLong();
- mLoadedStarts = in.readInt();
- mLoadedLaunches = in.readInt();
- mLastStartTime = 0;
- mLastStarts = 0;
- mLastLaunches = 0;
- mUnpluggedStartTime = in.readLong();
- mUnpluggedStarts = in.readInt();
- mUnpluggedLaunches = in.readInt();
}
public void writeToParcelLocked(Parcel out) {
@@ -9699,12 +9321,6 @@
out.writeLong(mLaunchedSince);
out.writeInt(mLaunched ? 1 : 0);
out.writeInt(mLaunches);
- out.writeLong(mLoadedStartTime);
- out.writeInt(mLoadedStarts);
- out.writeInt(mLoadedLaunches);
- out.writeLong(mUnpluggedStartTime);
- out.writeInt(mUnpluggedStarts);
- out.writeInt(mUnpluggedLaunches);
}
public long getLaunchTimeToNowLocked(long batteryUptime) {
@@ -9768,36 +9384,17 @@
@Override
public int getLaunches(int which) {
- int val = mLaunches;
- if (which == STATS_CURRENT) {
- val -= mLoadedLaunches;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedLaunches;
- }
- return val;
+ return mLaunches;
}
@Override
public long getStartTime(long now, int which) {
- long val = getStartTimeToNowLocked(now);
- if (which == STATS_CURRENT) {
- val -= mLoadedStartTime;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedStartTime;
- }
- return val;
+ return getStartTimeToNowLocked(now);
}
@Override
public int getStarts(int which) {
- int val = mStarts;
- if (which == STATS_CURRENT) {
- val -= mLoadedStarts;
- } else if (which == STATS_SINCE_UNPLUGGED) {
- val -= mUnpluggedStarts;
- }
-
- return val;
+ return mStarts;
}
}
@@ -10932,7 +10529,7 @@
}
mBluetoothActivity.reset(false);
mModemActivity.reset(false);
- mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0;
+ mNumConnectivityChange = 0;
for (int i=0; i<mUidStats.size(); i++) {
if (mUidStats.valueAt(i).reset(uptimeMillis * 1000, elapsedRealtimeMillis * 1000)) {
@@ -12668,7 +12265,7 @@
startRecordingHistory(elapsedRealtime, uptime, true);
}
} else if (level < 96 &&
- status != BatteryManager.BATTERY_STATUS_UNKNOWN) {
+ status != BatteryManager.BATTERY_STATUS_UNKNOWN) {
if (!mRecordingHistory) {
mRecordingHistory = true;
startRecordingHistory(elapsedRealtime, uptime, true);
@@ -12817,8 +12414,8 @@
}
}
if (!onBattery &&
- (status == BatteryManager.BATTERY_STATUS_FULL ||
- status == BatteryManager.BATTERY_STATUS_UNKNOWN)) {
+ (status == BatteryManager.BATTERY_STATUS_FULL ||
+ status == BatteryManager.BATTERY_STATUS_UNKNOWN)) {
// We don't record history while we are plugged in and fully charged
// (or when battery is not present). The next time we are
// unplugged, history will be cleared.
@@ -12855,7 +12452,9 @@
@UnsupportedAppUsage
public long getAwakeTimeBattery() {
- return computeBatteryUptime(getBatteryUptimeLocked(), STATS_CURRENT);
+ // This previously evaluated to mOnBatteryTimeBase.getUptime(getBatteryUptimeLocked());
+ // for over a decade, but surely that was a mistake.
+ return getBatteryUptimeLocked();
}
@UnsupportedAppUsage
@@ -12865,22 +12464,12 @@
@Override
public long computeUptime(long curTime, int which) {
- switch (which) {
- case STATS_SINCE_CHARGED: return mUptime + (curTime-mUptimeStart);
- case STATS_CURRENT: return (curTime-mUptimeStart);
- case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getUptimeStart());
- }
- return 0;
+ return mUptime + (curTime - mUptimeStart);
}
@Override
public long computeRealtime(long curTime, int which) {
- switch (which) {
- case STATS_SINCE_CHARGED: return mRealtime + (curTime-mRealtimeStart);
- case STATS_CURRENT: return (curTime-mRealtimeStart);
- case STATS_SINCE_UNPLUGGED: return (curTime-mOnBatteryTimeBase.getRealtimeStart());
- }
- return 0;
+ return mRealtime + (curTime - mRealtimeStart);
}
@Override
@@ -14074,7 +13663,7 @@
mHasBluetoothReporting = in.readInt() != 0;
mHasModemReporting = in.readInt() != 0;
- mNumConnectivityChange = mLoadedNumConnectivityChange = in.readInt();
+ mNumConnectivityChange = in.readInt();
mFlashlightOnNesting = 0;
mFlashlightOnTimer.readSummaryFromParcelLocked(in);
mCameraOnNesting = 0;
@@ -14383,12 +13972,12 @@
for (int ip = 0; ip < NP; ip++) {
String procName = in.readString();
Uid.Proc p = u.getProcessStatsLocked(procName);
- p.mUserTime = p.mLoadedUserTime = in.readLong();
- p.mSystemTime = p.mLoadedSystemTime = in.readLong();
- p.mForegroundTime = p.mLoadedForegroundTime = in.readLong();
- p.mStarts = p.mLoadedStarts = in.readInt();
- p.mNumCrashes = p.mLoadedNumCrashes = in.readInt();
- p.mNumAnrs = p.mLoadedNumAnrs = in.readInt();
+ p.mUserTime = in.readLong();
+ p.mSystemTime = in.readLong();
+ p.mForegroundTime = in.readLong();
+ p.mStarts = in.readInt();
+ p.mNumCrashes = in.readInt();
+ p.mNumAnrs = in.readInt();
p.readExcessivePowerFromParcelLocked(in);
}
@@ -14405,7 +13994,7 @@
throw new ParcelFormatException("File corrupt: too many wakeup alarms " + NWA);
}
p.mWakeupAlarms.clear();
- for (int iwa=0; iwa<NWA; iwa++) {
+ for (int iwa = 0; iwa < NWA; iwa++) {
String tag = in.readString();
Counter c = new Counter(mOnBatteryScreenOffTimeBase);
c.readSummaryFromParcelLocked(in);
@@ -14418,9 +14007,9 @@
for (int is = 0; is < NS; is++) {
String servName = in.readString();
Uid.Pkg.Serv s = u.getServiceStatsLocked(pkgName, servName);
- s.mStartTime = s.mLoadedStartTime = in.readLong();
- s.mStarts = s.mLoadedStarts = in.readInt();
- s.mLaunches = s.mLoadedLaunches = in.readInt();
+ s.mStartTime = in.readLong();
+ s.mStarts = in.readInt();
+ s.mLaunches = in.readInt();
}
}
}
@@ -15054,9 +14643,8 @@
mHasModemReporting = in.readInt() != 0;
mNumConnectivityChange = in.readInt();
- mLoadedNumConnectivityChange = in.readInt();
- mUnpluggedNumConnectivityChange = in.readInt();
mAudioOnNesting = 0;
+ // TODO: It's likely a mistake that mAudioOnTimer/mVideoOnTimer don't write/read to parcel!
mAudioOnTimer = new StopwatchTimer(mClocks, null, -7, null, mOnBatteryTimeBase);
mVideoOnNesting = 0;
mVideoOnTimer = new StopwatchTimer(mClocks, null, -8, null, mOnBatteryTimeBase);
@@ -15256,8 +14844,6 @@
out.writeInt(mHasModemReporting ? 1 : 0);
out.writeInt(mNumConnectivityChange);
- out.writeInt(mLoadedNumConnectivityChange);
- out.writeInt(mUnpluggedNumConnectivityChange);
mFlashlightOnTimer.writeToParcel(out, uSecRealtime);
mCameraOnTimer.writeToParcel(out, uSecRealtime);
mBluetoothScanTimer.writeToParcel(out, uSecRealtime);
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
index cd69d68..e31c9de 100644
--- a/core/java/com/android/internal/os/PowerCalculator.java
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -27,9 +27,10 @@
* @param u The recorded stats for the app.
* @param rawRealtimeUs The raw system realtime in microseconds.
* @param rawUptimeUs The raw system uptime in microseconds.
- * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT},
- * {@link BatteryStats#STATS_SINCE_CHARGED}, or
- * {@link BatteryStats#STATS_SINCE_UNPLUGGED}.
+ * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
+ * only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
+ * {@link BatteryStats#STATS_CURRENT} and
+ * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
*/
public abstract void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType);
@@ -40,9 +41,10 @@
* @param stats The BatteryStats object from which to retrieve data.
* @param rawRealtimeUs The raw system realtime in microseconds.
* @param rawUptimeUs The raw system uptime in microseconds.
- * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT},
- * {@link BatteryStats#STATS_SINCE_CHARGED}, or
- * {@link BatteryStats#STATS_SINCE_UNPLUGGED}.
+ * @param statsType The type of stats. As of {@link android.os.Build.VERSION_CODES#Q}, this can
+ * only be {@link BatteryStats#STATS_SINCE_CHARGED}, since
+ * {@link BatteryStats#STATS_CURRENT} and
+ * {@link BatteryStats#STATS_SINCE_UNPLUGGED} are deprecated.
*/
public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5f23719..07b82d0 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -122,6 +122,12 @@
private static boolean sPreloadComplete;
+ /**
+ * Cached classloader to use for the system server. Will only be populated in the system
+ * server process.
+ */
+ private static ClassLoader sCachedSystemServerClassLoader = null;
+
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
@@ -443,7 +449,13 @@
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
- performSystemServerDexOpt(systemServerClasspath);
+ if (performSystemServerDexOpt(systemServerClasspath)) {
+ // Throw away the cached classloader. If we compiled here, the classloader would
+ // not have had AoT-ed artifacts.
+ // Note: This only works in a very special environment where selinux enforcement is
+ // disabled, e.g., Mac builds.
+ sCachedSystemServerClassLoader = null;
+ }
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
boolean profileSystemServer = SystemProperties.getBoolean(
@@ -476,10 +488,9 @@
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
- ClassLoader cl = null;
- if (systemServerClasspath != null) {
- cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
-
+ createSystemServerClassLoader();
+ ClassLoader cl = sCachedSystemServerClassLoader;
+ if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}
@@ -494,6 +505,24 @@
}
/**
+ * Create the classloader for the system server and store it in
+ * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in
+ * system server startup, when the runtime is in a critically low state. Do not do
+ * extended computation etc here.
+ */
+ private static void createSystemServerClassLoader() {
+ if (sCachedSystemServerClassLoader != null) {
+ return;
+ }
+ final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
+ // TODO: Should we run optimization here?
+ if (systemServerClasspath != null) {
+ sCachedSystemServerClassLoader = createPathClassLoader(systemServerClasspath,
+ VMRuntime.SDK_VERSION_CUR_DEVELOPMENT);
+ }
+ }
+
+ /**
* Note that preparing the profiles for system server does not require special selinux
* permissions. From the installer perspective the system server is a regular package which can
* capture profile information.
@@ -557,15 +586,16 @@
/**
* Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
- * set of the current runtime.
+ * set of the current runtime. If something was compiled, return true.
*/
- private static void performSystemServerDexOpt(String classPath) {
+ private static boolean performSystemServerDexOpt(String classPath) {
final String[] classPathElements = classPath.split(":");
final IInstalld installd = IInstalld.Stub
.asInterface(ServiceManager.getService("installd"));
final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
String classPathForElement = "";
+ boolean compiledSomething = false;
for (String classPathElement : classPathElements) {
// System server is fully AOTed and never profiled
// for profile guided compilation.
@@ -607,6 +637,7 @@
uuid, classLoaderContext, seInfo, false /* downgrade */,
targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
"server-dexopt");
+ compiledSomething = true;
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -617,6 +648,8 @@
classPathForElement = encodeSystemServerClassPath(
classPathForElement, classPathElement);
}
+
+ return compiledSomething;
}
/**
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 9a346ac..60af511 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -96,6 +96,19 @@
return mBundle == null ? null : mBundle.getParcelable(EXTRA);
}
+ /**
+ * Gets the optional result from an operation that returns an extra {@code int} (besides the
+ * result code).
+ *
+ * @return value set in the bundle, or {@code defaultValue} when not set.
+ */
+ public int getOptionalExtraIntResult(int defaultValue) throws TimeoutException {
+ waitResult();
+ if (mBundle == null || !mBundle.containsKey(EXTRA)) return defaultValue;
+
+ return mBundle.getInt(EXTRA);
+ }
+
@Override
public void send(int resultCode, Bundle resultData) {
mResult = resultCode;
@@ -136,6 +149,18 @@
return bundle;
}
+ /**
+ * Creates a bundle for an {@code int} value so it can be retrieved by
+ * {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st
+ * is returned as the result code).
+ */
+ @NonNull
+ public static Bundle bundleFor(int value) {
+ final Bundle bundle = new Bundle();
+ bundle.putInt(EXTRA, value);
+ return bundle;
+ }
+
/** @hide */
public static final class TimeoutException extends RemoteException {
private TimeoutException(String msg) {
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 3be7c3e..41e2fc8 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -62,6 +62,7 @@
void systemReady();
void userPresent(int userId);
int getStrongAuthForUser(int userId);
+ boolean hasPendingEscrowToken(int userId);
// Keystore RecoveryController methods.
// {@code ServiceSpecificException} may be thrown to signal an error, which caller can
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index c095376..1965609 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1638,7 +1638,7 @@
}
/**
- * @see StrongAuthTracker#isFingerprintAllowedForUser
+ * @see StrongAuthTracker#isBiometricAllowedForUser(int)
*/
public boolean isBiometricAllowedForUser(int userId) {
return (getStrongAuthForUser(userId) & ~StrongAuthTracker.ALLOWING_BIOMETRIC) == 0;
@@ -1980,6 +1980,18 @@
}
/**
+ * Returns whether the given user has pending escrow tokens
+ */
+ public boolean hasPendingEscrowToken(int userId) {
+ try {
+ return getLockSettings().hasPendingEscrowToken(userId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
* Return true if the device supports the lock screen feature, false otherwise.
*/
public boolean hasSecureLockScreen() {
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 4773e16..3205b5a 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -20,12 +20,16 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
+import android.graphics.Path;
import android.graphics.RectF;
+import android.graphics.Region;
import android.hardware.input.InputManager;
import android.hardware.input.InputManager.InputDeviceListener;
+import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
+import android.view.ISystemGestureExclusionListener;
import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -34,6 +38,7 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowInsets;
+import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import java.util.ArrayList;
@@ -124,12 +129,16 @@
private int mActivePointerId;
private final ArrayList<PointerState> mPointers = new ArrayList<PointerState>();
private final PointerCoords mTempCoords = new PointerCoords();
-
+
+ private final Region mSystemGestureExclusion = new Region();
+ private final Path mSystemGestureExclusionPath = new Path();
+ private final Paint mSystemGestureExclusionPaint;
+
private final VelocityTracker mVelocity;
private final VelocityTracker mAltVelocity;
private final FasterStringBuilder mText = new FasterStringBuilder();
-
+
private boolean mPrintCoords = true;
public PointerLocationView(Context c) {
@@ -168,7 +177,11 @@
mPathPaint.setARGB(255, 0, 96, 255);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(1);
-
+
+ mSystemGestureExclusionPaint = new Paint();
+ mSystemGestureExclusionPaint.setARGB(25, 255, 0, 0);
+ mSystemGestureExclusionPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
PointerState ps = new PointerState();
mPointers.add(ps);
mActivePointerId = 0;
@@ -236,6 +249,12 @@
final int NP = mPointers.size();
+ if (!mSystemGestureExclusion.isEmpty()) {
+ mSystemGestureExclusionPath.reset();
+ mSystemGestureExclusion.getBoundaryPath(mSystemGestureExclusionPath);
+ canvas.drawPath(mSystemGestureExclusionPath, mSystemGestureExclusionPaint);
+ }
+
// Labels
if (mActivePointerId >= 0) {
final PointerState ps = mPointers.get(mActivePointerId);
@@ -719,6 +738,12 @@
super.onAttachedToWindow();
mIm.registerInputDeviceListener(this, getHandler());
+ try {
+ WindowManagerGlobal.getWindowManagerService().registerSystemGestureExclusionListener(
+ mSystemGestureExclusionListener, mContext.getDisplayId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
logInputDevices();
}
@@ -727,6 +752,12 @@
super.onDetachedFromWindow();
mIm.unregisterInputDeviceListener(this);
+ try {
+ WindowManagerGlobal.getWindowManagerService().unregisterSystemGestureExclusionListener(
+ mSystemGestureExclusionListener, mContext.getDisplayId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
@Override
@@ -876,4 +907,17 @@
return oldLength;
}
}
+
+ private ISystemGestureExclusionListener mSystemGestureExclusionListener =
+ new ISystemGestureExclusionListener.Stub() {
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion) {
+ Region exclusion = Region.obtain(systemGestureExclusion);
+ getHandler().post(() -> {
+ mSystemGestureExclusion.set(exclusion);
+ exclusion.recycle();
+ invalidate();
+ });
+ }
+ };
}
diff --git a/core/jni/android/graphics/HarfBuzzNGFaceSkia.h b/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
deleted file mode 100644
index 3308d5d..0000000
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2011, The Android Open Source Project
- * Copyright 2011, Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
-#define _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
-
-#include <SkScalar.h>
-#include <SkPaint.h>
-
-#include <hb.h>
-
-namespace android {
-
-static inline float
-HBFixedToFloat (hb_position_t v)
-{
- return scalbnf (v, -8);
-}
-
-static inline hb_position_t
-HBFloatToFixed (float v)
-{
- return scalbnf (v, +8);
-}
-
-static inline hb_position_t SkScalarToHBFixed(SkScalar value) {
- return HBFloatToFixed(SkScalarToFloat(value));
-}
-
-hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData);
-
-hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY);
-
-} // namespace android
-
-#endif // _ANDROID_GRAPHICS_HARF_BUZZ_NG_FACE_SKIA_H_
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index eb71052..a1d1d4f 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -31,6 +31,11 @@
namespace android {
+struct WeakRefHandleField {
+ jfieldID handle;
+ jmethodID get;
+};
+
static struct {
jfieldID ptr;
jfieldID inputApplicationHandle;
@@ -57,6 +62,8 @@
jfieldID inputFeatures;
jfieldID displayId;
jfieldID portalToDisplayId;
+ jfieldID replaceTouchableRegionWithCrop;
+ WeakRefHandleField touchableRegionCropHandle;
} gInputWindowHandleClassInfo;
static Mutex gHandleMutex;
@@ -90,6 +97,7 @@
jobject tokenObj = env->GetObjectField(obj, gInputWindowHandleClassInfo.token);
if (tokenObj) {
mInfo.token = ibinderForJavaObject(env, tokenObj);
+ env->DeleteLocalRef(tokenObj);
} else {
mInfo.token.clear();
}
@@ -161,6 +169,24 @@
env->DeleteLocalRef(inputApplicationHandleObj);
}
+ mInfo.replaceTouchableRegionWithCrop = env->GetBooleanField(obj,
+ gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop);
+
+ jobject handleObj = env->GetObjectField(obj,
+ gInputWindowHandleClassInfo.touchableRegionCropHandle.handle);
+ if (handleObj) {
+ // Promote java weak reference.
+ jobject strongHandleObj = env->CallObjectMethod(handleObj,
+ gInputWindowHandleClassInfo.touchableRegionCropHandle.get);
+ if (strongHandleObj) {
+ mInfo.touchableRegionCropHandle = ibinderForJavaObject(env, strongHandleObj);
+ env->DeleteLocalRef(strongHandleObj);
+ } else {
+ mInfo.touchableRegionCropHandle.clear();
+ }
+ env->DeleteLocalRef(handleObj);
+ }
+
env->DeleteLocalRef(obj);
return true;
}
@@ -220,6 +246,10 @@
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! (var), "Unable to find field " fieldName);
+#define GET_METHOD_ID(var, clazz, methodName, methodSignature) \
+ var = env->GetMethodID(clazz, methodName, methodSignature); \
+ LOG_FATAL_IF(! (var), "Unable to find method " methodName);
+
int register_android_view_InputWindowHandle(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "android/view/InputWindowHandle",
gInputWindowHandleMethods, NELEM(gInputWindowHandleMethods));
@@ -303,6 +333,18 @@
GET_FIELD_ID(gInputWindowHandleClassInfo.portalToDisplayId, clazz,
"portalToDisplayId", "I");
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.replaceTouchableRegionWithCrop, clazz,
+ "replaceTouchableRegionWithCrop", "Z");
+
+ jclass weakRefClazz;
+ FIND_CLASS(weakRefClazz, "java/lang/ref/Reference");
+
+ GET_METHOD_ID(gInputWindowHandleClassInfo.touchableRegionCropHandle.get, weakRefClazz,
+ "get", "()Ljava/lang/Object;")
+
+ GET_FIELD_ID(gInputWindowHandleClassInfo.touchableRegionCropHandle.handle, clazz,
+ "touchableRegionCropHandle", "Ljava/lang/ref/WeakReference;");
return 0;
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 9f9fbf9..c4c16ee 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -31,6 +31,7 @@
#include <renderthread/CanvasContext.h>
#include <TreeInfo.h>
#include <hwui/Paint.h>
+#include <utils/TraceUtils.h>
#include "core_jni_helpers.h"
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 009a6ca..cde1884 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -24,6 +24,7 @@
#endif
#define LOG_TAG "Zygote"
+#define ATRACE_TAG ATRACE_TAG_DALVIK
#include <async_safe/log.h>
@@ -73,6 +74,7 @@
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
+#include <utils/Trace.h>
#include <selinux/android.h>
#include <seccomp_policy.h>
#include <stats_event_list.h>
@@ -111,11 +113,16 @@
static const char kIsolatedStorage[] = "persist.sys.isolated_storage";
static const char kIsolatedStorageSnapshot[] = "sys.isolated_storage_snapshot";
-static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
+
+static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote";
static jclass gZygoteClass;
static jmethodID gCallPostForkSystemServerHooks;
static jmethodID gCallPostForkChildHooks;
+static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
+static jclass gZygoteInitClass;
+static jmethodID gCreateSystemServerClassLoader;
+
static bool g_is_security_enforced = true;
/**
@@ -585,6 +592,8 @@
}
static int UnmountTree(const char* path) {
+ ATRACE_CALL();
+
size_t path_len = strlen(path);
FILE* fp = setmntent("/proc/mounts", "r");
@@ -627,6 +636,8 @@
}
static void CreatePkgSandboxTarget(userid_t user_id, fail_fn_t fail_fn) {
+ ATRACE_CALL();
+
// Create /mnt/user/0/package
std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn);
@@ -650,6 +661,8 @@
uid_t uid,
const char* dir_name,
fail_fn_t fail_fn) {
+ ATRACE_CALL();
+
std::string mnt_source_dir = StringPrintf("%s/Android/%s/%s",
mnt_source_root.c_str(), dir_name, package_name.c_str());
@@ -662,6 +675,8 @@
static void CreateSubDirs(int parent_fd, const std::string& parent_path,
const std::vector<std::string>& sub_dirs,
fail_fn_t fail_fn) {
+ ATRACE_CALL();
+
for (auto& dir_name : sub_dirs) {
struct stat sb;
if (TEMP_FAILURE_RETRY(fstatat(parent_fd, dir_name.c_str(), &sb, 0)) == 0) {
@@ -686,6 +701,8 @@
const std::vector<std::string>& package_names,
bool create_sandbox_dir,
fail_fn_t fail_fn) {
+ ATRACE_CALL();
+
std::string android_dir = StringPrintf("%s/Android", path.c_str());
android::base::unique_fd android_fd(open(android_dir.c_str(),
O_RDONLY | O_DIRECTORY | O_CLOEXEC));
@@ -729,6 +746,7 @@
}
static void CreatePkgSandboxSource(const std::string& sandbox_source, fail_fn_t fail_fn) {
+ ATRACE_CALL();
struct stat sb;
if (TEMP_FAILURE_RETRY(stat(sandbox_source.c_str(), &sb)) == 0) {
@@ -751,6 +769,8 @@
static void PreparePkgSpecificDirs(const std::vector<std::string>& package_names,
bool mount_all_obbs, const std::string& sandbox_id,
userid_t user_id, uid_t uid, fail_fn_t fail_fn) {
+ ATRACE_CALL();
+
std::unique_ptr<DIR, decltype(&closedir)> dirp(opendir("/storage"), closedir);
if (!dirp) {
fail_fn(CREATE_ERROR("Failed to opendir /storage: %s", strerror(errno)));
@@ -807,6 +827,8 @@
userid_t user_id,
const std::string& sandbox_id,
fail_fn_t fail_fn) {
+ ATRACE_CALL();
+
std::string obb_mount_dir = StringPrintf("/mnt/user/%d/obb_mount", user_id);
std::string obb_mount_file = StringPrintf("%s/%s", obb_mount_dir.c_str(), sandbox_id.c_str());
if (mount_mode == MOUNT_EXTERNAL_INSTALLER) {
@@ -844,6 +866,7 @@
const std::string& sandbox_id,
fail_fn_t fail_fn) {
// See storage config details at http://source.android.com/tech/storage/
+ ATRACE_CALL();
String8 storage_source;
if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
@@ -1420,6 +1443,15 @@
fail_fn("Error calling post fork system server hooks.");
}
+ // Prefetch the classloader for the system server. This is done early to
+ // allow a tie-down of the proper system server selinux domain.
+ env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader);
+ if (env->ExceptionCheck()) {
+ // Be robust here. The Java code will attempt to create the classloader
+ // at a later point (but may not have rights to use AoT artifacts).
+ env->ExceptionClear();
+ }
+
// TODO(oth): Remove hardcoded label here (b/117874058).
static const char* kSystemServerLabel = "u:r:system_server:s0";
if (selinux_android_setcon(kSystemServerLabel) != 0) {
@@ -1986,6 +2018,13 @@
gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
"(IZZLjava/lang/String;)V");
- return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
+ gZygoteInitClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteInitClassName));
+ gCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass,
+ "createSystemServerClassLoader",
+ "()V");
+
+ RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
+
+ return JNI_OK;
}
} // namespace android
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 927c85f2..f037407 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2302,4 +2302,11 @@
// Panel for Wifi
PANEL_WIFI = 1687;
+
+ // Open: Settings > Special App Access > Do not disturb control for app
+ ZEN_ACCESS_DETAIL = 1692;
+
+ // OPEN: Settings > Face > Remove face
+ // OS: Q
+ DIALOG_FACE_REMOVE = 1693;
}
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 8fce94e..9bf1825 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -318,6 +318,16 @@
// Whether battery saver is enabled.
optional bool enabled = 1;
+ enum StateEnum {
+ STATE_UNKNOWN = 0;
+ STATE_OFF = 1;
+ STATE_MANUAL_ON = 2;
+ STATE_AUTOMATIC_ON = 3;
+ STATE_OFF_AUTOMATIC_SNOOZED = 4;
+ STATE_PENDING_STICKY_ON = 5;
+ }
+ optional StateEnum state = 18;
+
// Whether full battery saver is enabled.
optional bool is_full_enabled = 14;
@@ -337,8 +347,7 @@
// Whether battery status has been set at least once.
optional bool battery_status_set = 4;
- // Whether automatic battery saver has been canceled by the user.
- optional bool battery_saver_snoozing = 5;
+ reserved 5; // battery_saver_snoozing
// Whether the device is connected to any power source.
optional bool is_powered = 6;
@@ -373,5 +382,5 @@
// using elapsed realtime as the timebase.
optional int64 last_adaptive_battery_saver_changed_externally_elapsed = 17;
- // Next tag: 18
+ // Next tag: 19
}
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index c08d7ca..4ef26dd5 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -66,6 +66,10 @@
optional bool can_show_light = 8;
optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
optional sint32 importance = 10;
+ // The package the notification was posted for.
+ optional string package = 11;
+ // The package that posted the notification. It might not be the same as package.
+ optional string delegate_package = 12;
}
message ListenersDisablingEffectsProto {
diff --git a/core/java/android/net/ProxyInfoParcelable.aidl b/core/proto/android/stats/storage/storage_enums.proto
similarity index 74%
rename from core/java/android/net/ProxyInfoParcelable.aidl
rename to core/proto/android/stats/storage/storage_enums.proto
index 59fd846..6892e28 100644
--- a/core/java/android/net/ProxyInfoParcelable.aidl
+++ b/core/proto/android/stats/storage/storage_enums.proto
@@ -5,20 +5,22 @@
* 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
+ * 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.net;
+syntax = "proto2";
-parcelable ProxyInfoParcelable {
- String host;
- int port;
- String[] exclusionList;
- String pacFileUrl;
+package android.stats.storage;
+
+enum ExternalStorageType {
+ UNKNOWN = 0;
+ SD_CARD = 1;
+ USB = 2;
+ OTHER = 3;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c7417bf..5427147 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -819,8 +819,7 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_sdcardRead"
android:description="@string/permdesc_sdcardRead"
- android:protectionLevel="dangerous"
- android:permissionFlags="removed" />
+ android:protectionLevel="dangerous" />
<!-- Allows an application to write to external storage.
<p class="note"><strong>Note:</strong> If <em>both</em> your <a
@@ -841,8 +840,7 @@
android:permissionGroup="android.permission-group.UNDEFINED"
android:label="@string/permlab_sdcardWrite"
android:description="@string/permdesc_sdcardWrite"
- android:protectionLevel="dangerous"
- android:permissionFlags="removed" />
+ android:protectionLevel="dangerous" />
<!-- Runtime permission controlling access to the user's shared aural media
collection. -->
@@ -3929,6 +3927,10 @@
<permission android:name="android.permission.MANAGE_ROLLBACKS"
android:protectionLevel="signature|verifier" />
+ <!-- @SystemApi @TestApi @hide Allows testing apk level rollbacks. -->
+ <permission android:name="android.permission.TEST_MANAGE_ROLLBACKS"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi @hide Allows an application to mark other applications as harmful -->
<permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS"
android:protectionLevel="signature|verifier" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 743496f..9d48fe3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8108,7 +8108,7 @@
<!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a
{@link android.service.autofill.AutofillService}, which is referenced from its
- {@link android.service.autofill#SERVICE_META_DATA} meta-data entry.
+ {@link android.service.autofill.AutofillService#SERVICE_META_DATA} meta-data entry.
-->
<declare-styleable name="AutofillService">
<!-- Fully qualified class name of an activity that allows the user to modify
@@ -8134,6 +8134,23 @@
</declare-styleable>
<!-- =============================== -->
+ <!-- Content Capture attributes -->
+ <!-- =============================== -->
+ <eat-comment />
+
+ <!-- Use <code>content-capture-service</code> as the root tag of the XML resource that describes
+ a {@link android.service.contentcapture.ContentCaptureService}, which is referenced from
+ its {@link android.service.contentcapture.ContentCaptureService#SERVICE_META_DATA}
+ meta-data entry.
+ @hide @SystemApi
+ -->
+ <declare-styleable name="ContentCaptureService">
+ <!-- Fully qualified class name of an activity that allows the user to modify
+ the settings for this service. -->
+ <attr name="settingsActivity" />
+ </declare-styleable>
+
+ <!-- =============================== -->
<!-- Contacts meta-data attributes -->
<!-- =============================== -->
<eat-comment />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index dbea13e..fe2c665 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -118,8 +118,11 @@
<attr name="manageSpaceActivity" format="string" />
<!-- Option to let applications specify that user data can/cannot be
- cleared by the user in Settings. This flag is turned on by default.
- <em>This attribute is usable only by applications
+ cleared. This flag is turned on by default.
+ <p>Starting from API level 29 this flag only controls if the user can
+ clear app data from Settings. To control clearing the data after a
+ failed restore use allowClearUserDataOnFailedRestore flag.
+ <p><em>This attribute is usable only by applications
included in the system image. Third-party apps cannot use it.</em> -->
<attr name="allowClearUserData" format="boolean" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2b13c4e..74970e8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1538,43 +1538,45 @@
<string name="permdesc_useFaceAuthentication">Allows the app to use face authentication hardware for authentication</string>
<!-- Message shown during face acquisition when the face cannot be recognized [CHAR LIMIT=50] -->
- <string name="face_acquired_insufficient">Couldn\u2019t process face. Please try again.</string>
+ <string name="face_acquired_insufficient">Couldn\u2019t capture accurate face data. Try again.</string>
<!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
- <string name="face_acquired_too_bright">Face is too bright. Please try in lower light.</string>
+ <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
<!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
- <string name="face_acquired_too_dark">Face is too dark. Please uncover light source.</string>
+ <string name="face_acquired_too_dark">Too dark. Try brighter lighting.</string>
<!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_close">Please move sensor farther from face.</string>
+ <string name="face_acquired_too_close">Move phone farther away.</string>
<!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_far">Please bring sensor closer to face.</string>
+ <string name="face_acquired_too_far">Move phone closer.</string>
<!-- Message shown during face acquisition when the user is too high relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_high">Please move sensor higher.</string>
+ <string name="face_acquired_too_high">Move phone higher.</string>
<!-- Message shown during face acquisition when the user is too low relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_low">Please move sensor lower.</string>
+ <string name="face_acquired_too_low">Move phone lower.</string>
<!-- Message shown during face acquisition when the user is too right relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_right">Please move sensor to the right.</string>
+ <string name="face_acquired_too_right">Move phone to the right.</string>
<!-- Message shown during face acquisition when the user is too left relatively to sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_too_left">Please move sensor to the left.</string>
+ <string name="face_acquired_too_left">Move phone to the left.</string>
<!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
- <string name="face_acquired_poor_gaze">Please look at the sensor.</string>
+ <string name="face_acquired_poor_gaze">Look at the screen with your eyes open.</string>
<!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
- <string name="face_acquired_not_detected">No face detected.</string>
+ <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string>
<!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
- <string name="face_acquired_too_much_motion">Too much motion.</string>
+ <string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
<!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
<string name="face_acquired_recalibrate">Please re-enroll your face.</string>
<!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
- <string name="face_acquired_too_different">Different face detected.</string>
+ <string name="face_acquired_too_different">No longer able to recognize face. Try again.</string>
<!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
<string name="face_acquired_too_similar">Too similar, please change your pose.</string>
<!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
- <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string>
+ <string name="face_acquired_pan_too_extreme">Please look more directly at the screen.</string>
<!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
- <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string>
+ <string name="face_acquired_tilt_too_extreme">Please look more directly at the screen.</string>
<!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
<string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string>
<!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
- <string name="face_acquired_obscured">Please uncover your face.</string>
+ <string name="face_acquired_obscured">Clear the space between your head and the phone.</string>
+ <!-- Message shown during acquisition when the sensor is dirty [CHAR LIMIT=50] -->
+ <string name="face_acquired_sensor_dirty">Please clean the camera.</string>
<!-- Array containing custom messages shown during face acquisition from vendor. Vendor is expected to add and translate these strings -->
<string-array name="face_acquired_vendor">
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 97593ff..17ccc31 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2546,6 +2546,7 @@
<java-symbol type="string" name="face_acquired_tilt_too_extreme" />
<java-symbol type="string" name="face_acquired_roll_too_extreme" />
<java-symbol type="string" name="face_acquired_obscured" />
+ <java-symbol type="string" name="face_acquired_sensor_dirty" />
<java-symbol type="array" name="face_acquired_vendor" />
<java-symbol type="string" name="face_name_template" />
<java-symbol type="string" name="face_authenticated_no_confirmation_required" />
@@ -3681,6 +3682,7 @@
<java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" />
<java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" />
<java-symbol type="drawable" name="ic_action_open" />
+ <java-symbol type="drawable" name="ic_menu_copy_material" />
<!-- MIME types -->
<java-symbol type="string" name="mime_type_folder" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 7322a54..6fb4744 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -656,6 +656,7 @@
Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME,
Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
Settings.Secure.ODI_CAPTIONS_ENABLED,
+ Settings.Secure.ODI_CAPTIONS_OPTED_OUT,
Settings.Secure.PACKAGE_VERIFIER_STATE,
Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT,
Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE,
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 66146c9..4266ba9f 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -24,10 +24,16 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.app.Instrumentation;
+import android.content.Context;
import android.graphics.Point;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl.Transaction;
+import android.view.WindowManager.BadTokenException;
+import android.view.WindowManager.LayoutParams;
+import android.widget.TextView;
+import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
@@ -47,7 +53,6 @@
private SurfaceSession mSession = new SurfaceSession();
private SurfaceControl mLeash;
@Mock Transaction mMockTransaction;
- @Mock InsetsController mMockController;
@Before
public void setup() {
@@ -55,8 +60,21 @@
mLeash = new SurfaceControl.Builder(mSession)
.setName("testSurface")
.build();
- mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, new InsetsState(),
- () -> mMockTransaction, mMockController);
+ final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ instrumentation.runOnMainSync(() -> {
+ final Context context = instrumentation.getTargetContext();
+ // cannot mock ViewRootImpl since it's final.
+ final ViewRootImpl viewRootImpl = new ViewRootImpl(context, context.getDisplay());
+ try {
+ viewRootImpl.setView(new TextView(context), new LayoutParams(), null);
+ } catch (BadTokenException e) {
+ // activity isn't running, lets ignore BadTokenException.
+ }
+ mConsumer = new InsetsSourceConsumer(TYPE_TOP_BAR, new InsetsState(),
+ () -> mMockTransaction, new InsetsController(viewRootImpl));
+ });
+ instrumentation.waitForIdleSync();
+
mConsumer.setControl(new InsetsSourceControl(TYPE_TOP_BAR, mLeash, new Point()));
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
index 7150d81..5c7287f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/ActionsSuggestionsHelperTest.java
@@ -27,13 +27,17 @@
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.drawable.Icon;
+import android.net.Uri;
import android.os.Bundle;
+import android.view.textclassifier.intent.LabeledIntent;
+import android.view.textclassifier.intent.TemplateIntentFactory;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.google.android.textclassifier.ActionsSuggestionsModel;
+import com.google.android.textclassifier.RemoteActionTemplate;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -204,6 +208,77 @@
assertThat(conversationActions.get(2).getAction()).isNull();
}
+ public void createLabeledIntentResult_null() {
+ ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
+ new ActionsSuggestionsModel.ActionSuggestion(
+ "text",
+ ConversationAction.TYPE_OPEN_URL,
+ 1.0f,
+ null,
+ null
+ );
+
+ LabeledIntent.Result labeledIntentResult =
+ ActionsSuggestionsHelper.createLabeledIntentResult(
+ InstrumentationRegistry.getTargetContext(),
+ new TemplateIntentFactory(),
+ nativeSuggestion);
+
+ assertThat(labeledIntentResult).isNull();
+ }
+
+ @Test
+ public void createLabeledIntentResult_emptyList() {
+ ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
+ new ActionsSuggestionsModel.ActionSuggestion(
+ "text",
+ ConversationAction.TYPE_OPEN_URL,
+ 1.0f,
+ null,
+ new RemoteActionTemplate[0]
+ );
+
+ LabeledIntent.Result labeledIntentResult =
+ ActionsSuggestionsHelper.createLabeledIntentResult(
+ InstrumentationRegistry.getTargetContext(),
+ new TemplateIntentFactory(),
+ nativeSuggestion);
+
+ assertThat(labeledIntentResult).isNull();
+ }
+
+ @Test
+ public void createLabeledIntentResult() {
+ ActionsSuggestionsModel.ActionSuggestion nativeSuggestion =
+ new ActionsSuggestionsModel.ActionSuggestion(
+ "text",
+ ConversationAction.TYPE_OPEN_URL,
+ 1.0f,
+ null,
+ new RemoteActionTemplate[]{
+ new RemoteActionTemplate(
+ "title",
+ null,
+ "description",
+ Intent.ACTION_VIEW,
+ Uri.parse("http://www.android.com").toString(),
+ null,
+ 0,
+ null,
+ null,
+ null,
+ 0)});
+
+ LabeledIntent.Result labeledIntentResult =
+ ActionsSuggestionsHelper.createLabeledIntentResult(
+ InstrumentationRegistry.getTargetContext(),
+ new TemplateIntentFactory(),
+ nativeSuggestion);
+
+ assertThat(labeledIntentResult.remoteAction.getTitle()).isEqualTo("title");
+ assertThat(labeledIntentResult.resolvedIntent.getAction()).isEqualTo(Intent.ACTION_VIEW);
+ }
+
private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneId.of("UTC"));
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
index fef6583..2674e37 100644
--- a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
+++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
@@ -44,8 +44,7 @@
/**
* A builder used to build a fake context for testing.
*/
-// TODO: Consider making public.
-final class FakeContextBuilder {
+public final class FakeContextBuilder {
/**
* A component name that can be used for tests.
@@ -57,7 +56,7 @@
private final Map<String, ComponentName> mComponents = new HashMap<>();
private @Nullable ComponentName mAllIntentComponent;
- FakeContextBuilder() {
+ public FakeContextBuilder() {
mPackageManager = mock(PackageManager.class);
when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(null);
mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index fe2a660..f6bb1bf 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -21,6 +21,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -48,7 +49,8 @@
+ "entity_list_editable=date:datetime,"
+ "in_app_conversation_action_types_default=text_reply,"
+ "notification_conversation_action_types_default=send_email:call_phone,"
- + "lang_id_threshold_override=0.3";
+ + "lang_id_threshold_override=0.3,"
+ + "lang_id_context_settings=10:1:0.5";
final TextClassificationConstants constants =
TextClassificationConstants.loadFromString(s);
@@ -91,6 +93,8 @@
.containsExactly("send_email", "call_phone");
assertWithMessage("lang_id_threshold_override")
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f);
+ Assert.assertArrayEquals("lang_id_context_settings",
+ constants.getLangIdContextSettings(), new float[]{10, 1, 0.5f}, EPSILON);
}
@Test
@@ -111,7 +115,8 @@
+ "entity_list_editable=flight,"
+ "in_app_conversation_action_types_default=view_map:track_flight,"
+ "notification_conversation_action_types_default=share_location,"
- + "lang_id_threshold_override=2";
+ + "lang_id_threshold_override=2,"
+ + "lang_id_context_settings=30:0.5:0.3";
final TextClassificationConstants constants =
TextClassificationConstants.loadFromString(s);
@@ -154,6 +159,8 @@
.containsExactly("share_location");
assertWithMessage("lang_id_threshold_override")
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
+ Assert.assertArrayEquals("lang_id_context_settings",
+ constants.getLangIdContextSettings(), new float[]{30, 0.5f, 0.3f}, EPSILON);
}
@Test
@@ -196,13 +203,15 @@
.that(constants.getInAppConversationActionTypes())
.containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
"send_email", "send_sms", "track_flight", "view_calendar", "view_map",
- "add_contact");
+ "add_contact", "copy");
assertWithMessage("notification_conversation_action_types_default")
.that(constants.getNotificationConversationActionTypes())
.containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
"send_email", "send_sms", "track_flight", "view_calendar", "view_map",
- "add_contact");
+ "add_contact", "copy");
assertWithMessage("lang_id_threshold_override")
.that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
+ Assert.assertArrayEquals("lang_id_context_settings",
+ constants.getLangIdContextSettings(), new float[]{20, 1, 0.4f}, EPSILON);
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index bcaf663..8de5f13 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -32,6 +32,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
import com.google.common.truth.Truth;
@@ -41,7 +42,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collections;
@@ -53,22 +53,10 @@
* Tests are skipped if such a textclassifier does not exist.
*/
@SmallTest
-@RunWith(Parameterized.class)
+@RunWith(AndroidJUnit4.class)
public class TextClassifierTest {
- private static final String LOCAL = "local";
- private static final String SYSTEM = "system";
- @Parameterized.Parameters(name = "{0}")
- public static Iterable<Object> textClassifierTypes() {
- return Arrays.asList(LOCAL);
-
- // TODO: The following will fail on any device that specifies a no-op TextClassifierService.
- // Enable when we can set a specified TextClassifierService for testing.
- // return Arrays.asList(LOCAL, SYSTEM);
- }
-
- @Parameterized.Parameter
- public String mTextClassifierType;
+ // TODO: Implement TextClassifierService testing.
private static final TextClassificationConstants TC_CONSTANTS =
TextClassificationConstants.loadFromString("");
@@ -83,8 +71,7 @@
public void setup() {
mContext = InstrumentationRegistry.getTargetContext();
mTcm = mContext.getSystemService(TextClassificationManager.class);
- mClassifier = mTcm.getTextClassifier(
- mTextClassifierType.equals(LOCAL) ? TextClassifier.LOCAL : TextClassifier.SYSTEM);
+ mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
}
@Test
@@ -278,6 +265,8 @@
assertEquals("ja", ExtrasUtils.getEntityType(foreignLanguageInfo));
assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) >= 0);
assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) <= 1);
+ assertTrue(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER));
+ assertEquals("ja", ExtrasUtils.getTopLanguage(intent).getLanguage());
LocaleList.setDefault(originalLocales);
}
@@ -468,6 +457,34 @@
Truth.assertThat(actionIntent.getData()).isEqualTo(Uri.parse("https://www.android.com"));
}
+ @Test
+ public void testSuggestConversationActions_copy() {
+ if (isTextClassifierDisabled()) return;
+ ConversationActions.Message message =
+ new ConversationActions.Message.Builder(
+ ConversationActions.Message.PERSON_USER_OTHERS)
+ .setText("Authentication code: 12345")
+ .build();
+ TextClassifier.EntityConfig typeConfig =
+ new TextClassifier.EntityConfig.Builder().includeTypesFromTextClassifier(false)
+ .setIncludedTypes(
+ Collections.singletonList(ConversationAction.TYPE_COPY))
+ .build();
+ ConversationActions.Request request =
+ new ConversationActions.Request.Builder(Collections.singletonList(message))
+ .setMaxSuggestions(1)
+ .setTypeConfig(typeConfig)
+ .build();
+
+ ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+ Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
+ ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
+ Truth.assertThat(conversationAction.getType()).isEqualTo(ConversationAction.TYPE_COPY);
+ Truth.assertThat(conversationAction.getTextReply()).isAnyOf(null, "");
+ Truth.assertThat(conversationAction.getAction()).isNull();
+ String code = ExtrasUtils.getCopyText(conversationAction.getExtras());
+ Truth.assertThat(code).isEqualTo("12345");
+ }
private boolean isTextClassifierDisabled() {
return mClassifier == null || mClassifier == TextClassifier.NO_OP;
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierUtilsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierUtilsTest.java
new file mode 100644
index 0000000..011866d
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierUtilsTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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 android.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TextClassifierUtilsTest {
+
+ @Test
+ public void testGetSubString() {
+ final String text = "Yakuza call themselves ä»»ä¾ å›£ä½“";
+ int start;
+ int end;
+ int minimumLength;
+
+ // End index at end of text.
+ start = text.indexOf("ä»»ä¾ å›£ä½“");
+ end = text.length();
+ minimumLength = 20;
+ assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+ .isEqualTo("call themselves ä»»ä¾ å›£ä½“");
+
+ // Start index at beginning of text.
+ start = 0;
+ end = "Yakuza".length();
+ minimumLength = 15;
+ assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+ .isEqualTo("Yakuza call themselves");
+
+ // Text in the middle
+ start = text.indexOf("all");
+ end = start + 1;
+ minimumLength = 10;
+ assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+ .isEqualTo("Yakuza call themselves");
+
+ // Selection >= minimumLength.
+ start = text.indexOf("themselves");
+ end = start + "themselves".length();
+ minimumLength = end - start;
+ assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+ .isEqualTo("themselves");
+
+ // text.length < minimumLength.
+ minimumLength = text.length() + 1;
+ assertThat(TextClassifier.Utils.getSubString(text, start, end, minimumLength))
+ .isEqualTo(text);
+ }
+
+ @Test
+ public void testGetSubString_invalidParams() {
+ final String text = "The Yoruba regard Olodumare as the principal agent of creation";
+ final int length = text.length();
+ final int minimumLength = 10;
+
+ // Null text
+ assertThrows(() -> TextClassifier.Utils.getSubString(null, 0, 1, minimumLength));
+ // start > end
+ assertThrows(() -> TextClassifier.Utils.getSubString(text, 6, 5, minimumLength));
+ // start < 0
+ assertThrows(() -> TextClassifier.Utils.getSubString(text, -1, 5, minimumLength));
+ // end > text.length
+ assertThrows(() -> TextClassifier.Utils.getSubString(text, 6, length + 1, minimumLength));
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
similarity index 79%
rename from core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
index 6520c8f..857408f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LabeledIntentTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LabeledIntentTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import static com.google.common.truth.Truth.assertThat;
@@ -23,8 +23,10 @@
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import android.os.Bundle;
+import android.view.textclassifier.FakeContextBuilder;
+import android.view.textclassifier.TextClassifier;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -41,11 +43,15 @@
private static final Intent INTENT =
new Intent(Intent.ACTION_VIEW).setDataAndNormalize(Uri.parse("http://www.android.com"));
private static final int REQUEST_CODE = 42;
+ private static final Bundle TEXT_LANGUAGES_BUNDLE = Bundle.EMPTY;
+
private Context mContext;
@Before
public void setup() {
- mContext = InstrumentationRegistry.getTargetContext();
+ mContext = new FakeContextBuilder()
+ .setIntentComponent(Intent.ACTION_VIEW, FakeContextBuilder.DEFAULT_COMPONENT)
+ .build();
}
@Test
@@ -58,8 +64,8 @@
REQUEST_CODE
);
- LabeledIntent.Result result =
- labeledIntent.resolve(mContext, /*titleChooser*/ null);
+ LabeledIntent.Result result = labeledIntent.resolve(
+ mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
assertThat(result).isNotNull();
assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITH_ENTITY);
@@ -67,6 +73,7 @@
Intent intent = result.resolvedIntent;
assertThat(intent.getAction()).isEqualTo(intent.getAction());
assertThat(intent.getComponent()).isNotNull();
+ assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@Test
@@ -79,8 +86,8 @@
REQUEST_CODE
);
- LabeledIntent.Result result =
- labeledIntent.resolve(mContext, /*titleChooser*/ null);
+ LabeledIntent.Result result = labeledIntent.resolve(
+ mContext, /*titleChooser*/ null, TEXT_LANGUAGES_BUNDLE);
assertThat(result).isNotNull();
assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
@@ -100,8 +107,8 @@
REQUEST_CODE
);
- LabeledIntent.Result result =
- labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> "chooser");
+ LabeledIntent.Result result = labeledIntent.resolve(
+ mContext, (labeledIntent1, resolveInfo) -> "chooser", TEXT_LANGUAGES_BUNDLE);
assertThat(result).isNotNull();
assertThat(result.remoteAction.getTitle()).isEqualTo("chooser");
@@ -121,8 +128,8 @@
REQUEST_CODE
);
- LabeledIntent.Result result =
- labeledIntent.resolve(mContext, (labeledIntent1, resolveInfo) -> null);
+ LabeledIntent.Result result = labeledIntent.resolve(
+ mContext, (labeledIntent1, resolveInfo) -> null, TEXT_LANGUAGES_BUNDLE);
assertThat(result).isNotNull();
assertThat(result.remoteAction.getTitle()).isEqualTo(TITLE_WITHOUT_ENTITY);
@@ -148,15 +155,16 @@
@Test
public void resolve_noIntentHandler() {
- Intent intent = new Intent("some.thing.does.not.exist");
+ // See setup(). mContext can only resolve Intent.ACTION_VIEW.
+ Intent unresolvableIntent = new Intent(Intent.ACTION_TRANSLATE);
LabeledIntent labeledIntent = new LabeledIntent(
TITLE_WITHOUT_ENTITY,
null,
DESCRIPTION,
- intent,
+ unresolvableIntent,
REQUEST_CODE);
- LabeledIntent.Result result = labeledIntent.resolve(mContext, null);
+ LabeledIntent.Result result = labeledIntent.resolve(mContext, null, null);
assertThat(result).isNull();
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
similarity index 85%
rename from core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
index 2a79c1c..19e5b0a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/LegacyIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/LegacyIntentClassificationFactoryTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import static com.google.common.truth.Truth.assertThat;
import android.content.Intent;
+import android.view.textclassifier.TextClassifier;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -34,15 +35,15 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class LegacyIntentFactoryTest {
+public class LegacyIntentClassificationFactoryTest {
private static final String TEXT = "text";
- private LegacyIntentFactory mLegacyIntentFactory;
+ private LegacyClassificationIntentFactory mLegacyIntentClassificationFactory;
@Before
public void setup() {
- mLegacyIntentFactory = new LegacyIntentFactory();
+ mLegacyIntentClassificationFactory = new LegacyClassificationIntentFactory();
}
@Test
@@ -64,7 +65,7 @@
null,
null);
- List<LabeledIntent> intents = mLegacyIntentFactory.create(
+ List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
InstrumentationRegistry.getContext(),
TEXT,
/* foreignText */ false,
@@ -76,8 +77,6 @@
Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_DEFINE);
assertThat(intent.getStringExtra(Intent.EXTRA_TEXT)).isEqualTo(TEXT);
- assertThat(
- intent.getBooleanExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER, false)).isTrue();
}
@Test
@@ -99,7 +98,7 @@
null,
null);
- List<LabeledIntent> intents = mLegacyIntentFactory.create(
+ List<LabeledIntent> intents = mLegacyIntentClassificationFactory.create(
InstrumentationRegistry.getContext(),
TEXT,
/* foreignText */ true,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
similarity index 66%
rename from core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
index fac58f8..eaef0a0 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateClassificationIntentFactoryTest.java
@@ -14,11 +14,19 @@
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
import android.content.Intent;
+import android.view.textclassifier.TextClassifier;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -45,7 +53,7 @@
private static final String ACTION = Intent.ACTION_VIEW;
@Mock
- private IntentFactory mFallback;
+ private ClassificationIntentFactory mFallback;
private TemplateClassificationIntentFactory mTemplateClassificationIntentFactory;
@Before
@@ -88,12 +96,10 @@
assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(ACTION);
- assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
labeledIntent = intents.get(1);
intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(Intent.ACTION_TRANSLATE);
- assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@Test
@@ -128,9 +134,73 @@
assertThat(labeledIntent.titleWithoutEntity).isEqualTo(TITLE_WITHOUT_ENTITY);
Intent intent = labeledIntent.intent;
assertThat(intent.getAction()).isEqualTo(ACTION);
- assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
+ @Test
+ public void create_nullTemplate() {
+ AnnotatorModel.ClassificationResult classificationResult =
+ new AnnotatorModel.ClassificationResult(
+ TextClassifier.TYPE_ADDRESS,
+ 1.0f,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null);
+
+ mTemplateClassificationIntentFactory.create(
+ InstrumentationRegistry.getContext(),
+ TEXT,
+ /* foreignText */ false,
+ null,
+ classificationResult);
+
+
+ verify(mFallback).create(
+ same(InstrumentationRegistry.getContext()), eq(TEXT), eq(false), eq(null),
+ same(classificationResult));
+ }
+
+ @Test
+ public void create_emptyResult() {
+ AnnotatorModel.ClassificationResult classificationResult =
+ new AnnotatorModel.ClassificationResult(
+ TextClassifier.TYPE_ADDRESS,
+ 1.0f,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ null,
+ new RemoteActionTemplate[0]);
+
+ mTemplateClassificationIntentFactory.create(
+ InstrumentationRegistry.getContext(),
+ TEXT,
+ /* foreignText */ false,
+ null,
+ classificationResult);
+
+
+ verify(mFallback, never()).create(
+ any(Context.class), eq(TEXT), eq(false), eq(null),
+ any(AnnotatorModel.ClassificationResult.class));
+ }
+
+
private static RemoteActionTemplate[] createRemoteActionTemplates() {
return new RemoteActionTemplate[]{
new RemoteActionTemplate(
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
similarity index 97%
rename from core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
rename to core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
index 1860734..6e3de2d 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/intent/TemplateIntentFactoryTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.view.textclassifier;
+package android.view.textclassifier.intent;
import static com.google.common.truth.Truth.assertThat;
@@ -101,7 +101,6 @@
assertThat(intent.getPackage()).isNull();
assertThat(intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
assertThat(intent.getIntExtra(KEY_TWO, 0)).isEqualTo(VALUE_TWO);
- assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@Test
@@ -160,7 +159,6 @@
assertThat(intent.getFlags()).isEqualTo(0);
assertThat(intent.getCategories()).isNull();
assertThat(intent.getPackage()).isNull();
- assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
index 37f818a..ade3a99 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsCounterTest.java
@@ -44,8 +44,6 @@
counter.stepAtomic();
counter.stepAtomic();
assertEquals(0, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(0, counter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(0, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase on (i.e. unplugged)
timeBase.setRunning(true, 2, 2);
@@ -54,8 +52,6 @@
counter.stepAtomic();
counter.stepAtomic();
assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(4, counter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase off (i.e. plugged in)
timeBase.setRunning(false, 3, 3);
@@ -63,16 +59,12 @@
counter.stepAtomic();
counter.stepAtomic();
assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(4, counter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(4, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase on (i.e. unplugged)
timeBase.setRunning(true, 4, 4);
counter.stepAtomic();
counter.stepAtomic();
assertEquals(6, counter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(6, counter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(2, counter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
}
@@ -88,8 +80,6 @@
timeBase.setRunning(true, 1, 1);
origCounter.stepAtomic(); origCounter.stepAtomic(); origCounter.stepAtomic(); // three times
assertEquals(3, origCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(3, origCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(3, origCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// Test summary parcelling (from origCounter)
final Parcel summaryParcel = Parcel.obtain();
@@ -102,22 +92,16 @@
// timeBase still on (i.e. unplugged)
summaryCounter.stepAtomic(); // once
assertEquals(4, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase off (i.e. plugged in)
timeBase.setRunning(false, 3, 3);
summaryCounter.stepAtomic(); summaryCounter.stepAtomic(); // twice
assertEquals(4, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(1, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase on (i.e. unplugged)
timeBase.setRunning(true, 4, 4);
summaryCounter.stepAtomic(); summaryCounter.stepAtomic(); // twice
assertEquals(6, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(3, summaryCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(2, summaryCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// Test full parcelling (from summaryCounter)
@@ -130,21 +114,15 @@
// timeBase still on (i.e. unplugged)
fullParcelCounter.stepAtomic(); // once
assertEquals(7, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(4, fullParcelCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(3, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase off (i.e. plugged in)
timeBase.setRunning(false, 5, 5);
fullParcelCounter.stepAtomic(); fullParcelCounter.stepAtomic(); // twice
assertEquals(7, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(4, fullParcelCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(3, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
// timeBase on (i.e. unplugged)
timeBase.setRunning(true, 6, 6);
fullParcelCounter.stepAtomic(); fullParcelCounter.stepAtomic(); // twice
assertEquals(9, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
- assertEquals(6, fullParcelCounter.getCountLocked(BatteryStats.STATS_CURRENT));
- assertEquals(2, fullParcelCounter.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
index a42286f..78fa3fb 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsDurationTimerTest.java
@@ -100,8 +100,70 @@
assertEquals(30802, timer.getTotalDurationMsLocked(220302));
}
+ /**
+ * Tests that reset(boolean detachIfReset) clears the correct times if detachIfReset is false.
+ */
@SmallTest
public void testReset() throws Exception {
+ final MockClocks clocks = new MockClocks();
+
+ final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
+ timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
+
+ final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks,
+ null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+
+ timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100_000);
+ timer.startRunningLocked(700);
+ timer.stopRunningLocked(3_100);
+ assertFalse(timer.isRunningLocked());
+ assertEquals(0, timer.getCurrentDurationMsLocked(6_300));
+ assertEquals(2_400, timer.getMaxDurationMsLocked(6_301));
+ assertEquals(2_400, timer.getTotalDurationMsLocked(6_302));
+
+ timer.reset(false);
+ assertEquals(0, timer.getCurrentDurationMsLocked(12_000));
+ assertEquals(0, timer.getMaxDurationMsLocked(12_001));
+ assertEquals(0, timer.getTotalDurationMsLocked(12_002));
+
+ assertEquals(true, timeBase.hasObserver(timer));
+
+ timer.startRunningLocked(24_100);
+ clocks.uptime = clocks.realtime = 24_200;
+ timer.reset(false);
+ assertEquals(34_300, timer.getCurrentDurationMsLocked(58_500));
+ assertEquals(34_301, timer.getMaxDurationMsLocked(58_501));
+ assertEquals(34_302, timer.getTotalDurationMsLocked(58_502));
+ }
+
+ /**
+ * Tests that reset(boolean detachIfReset) clears the correct times if detachIfReset is true.
+ */
+ @SmallTest
+ public void testResetAndDetach() throws Exception {
+ final MockClocks clocks = new MockClocks();
+
+ final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
+ timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
+
+ final BatteryStatsImpl.DurationTimer timer = new BatteryStatsImpl.DurationTimer(clocks,
+ null, BatteryStats.WAKE_TYPE_PARTIAL, null, timeBase);
+
+ timeBase.setRunning(true, /* uptimeUs */ 0, /* realtimeUs */ 100_000);
+ timer.startRunningLocked(700);
+ timer.stopRunningLocked(3_100);
+ assertFalse(timer.isRunningLocked());
+ assertEquals(0, timer.getCurrentDurationMsLocked(6_300));
+ assertEquals(2_400, timer.getMaxDurationMsLocked(6_301));
+ assertEquals(2_400, timer.getTotalDurationMsLocked(6_302));
+
+ timer.reset(true);
+ clocks.uptime = clocks.realtime = 7_000;
+ assertEquals(0, timer.getCurrentDurationMsLocked(8_000));
+ assertEquals(0, timer.getMaxDurationMsLocked(8_001));
+ assertEquals(0, timer.getTotalDurationMsLocked(8_002));
+
+ assertEquals(false, timeBase.hasObserver(timer));
}
@SmallTest
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
index 0771829..4b37dd2 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsImplTest.java
@@ -325,7 +325,7 @@
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
- BatteryStats.STATS_SINCE_UNPLUGGED);
+ BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
(releaseTimeMs - acquireTimeMs) * 1000, totalTime);
}
@@ -347,7 +347,7 @@
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
- BatteryStats.STATS_SINCE_UNPLUGGED);
+ BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
(currentTimeMs - acquireTimeMs) * 1000, totalTime);
}
@@ -377,7 +377,7 @@
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
- BatteryStats.STATS_SINCE_UNPLUGGED);
+ BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
(releaseTimeMs_2 - acquireTimeMs_1) * 1000, totalTime);
}
@@ -407,7 +407,7 @@
// Get the total acquisition time
long totalTime = u.getWifiMulticastTime(currentTimeMs*1000,
- BatteryStats.STATS_SINCE_UNPLUGGED);
+ BatteryStats.STATS_SINCE_CHARGED);
assertEquals("Miscalculations of Multicast wakelock acquisition time",
((releaseTimeMs_1 - acquireTimeMs_1) + (releaseTimeMs_2 - acquireTimeMs_2))
* 1000, totalTime);
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
index 3e33273..8f5dfc5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsNoteTest.java
@@ -16,7 +16,6 @@
package com.android.internal.os;
-import static android.os.BatteryStats.STATS_CURRENT;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import static android.os.BatteryStats.WAKE_TYPE_PARTIAL;
@@ -388,7 +387,7 @@
bi.noteWakupAlarmLocked("com.foo.bar", UID, null, "tag");
Uid.Pkg pkg = bi.getPackageStatsLocked(UID, "com.foo.bar");
- assertEquals(1, pkg.getWakeupAlarmStats().get("tag").getCountLocked(STATS_CURRENT));
+ assertEquals(1, pkg.getWakeupAlarmStats().get("tag").getCountLocked(STATS_SINCE_CHARGED));
assertEquals(1, pkg.getWakeupAlarmStats().size());
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
index b9995c4..df549c5 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsServTest.java
@@ -44,15 +44,6 @@
mLaunchedSince = 6064;
mLaunched = true;
mLaunches = 8085;
- mLoadedStartTime = 9096;
- mLoadedStarts = 10017;
- mLoadedLaunches = 11118;
- mLastStartTime = 12219;
- mLastStarts = 13310;
- mLastLaunches = 14411;
- mUnpluggedStartTime = 15512;
- mUnpluggedStarts = 16613;
- mUnpluggedLaunches = 17714;
}
long getStartTime() {
@@ -94,42 +85,6 @@
int getLaunches() {
return mLaunches;
}
-
- long getLoadedStartTime() {
- return mLoadedStartTime;
- }
-
- int getLoadedStarts() {
- return mLoadedStarts;
- }
-
- int getLoadedLaunches() {
- return mLoadedLaunches;
- }
-
- long getLastStartTime() {
- return mLastStartTime;
- }
-
- int getLastStarts() {
- return mLastStarts;
- }
-
- int getLastLaunches() {
- return mLastLaunches;
- }
-
- long getUnpluggedStartTime() {
- return mUnpluggedStartTime;
- }
-
- int getUnpluggedStarts() {
- return mUnpluggedStarts;
- }
-
- int getUnpluggedLaunches() {
- return mUnpluggedLaunches;
- }
}
/**
@@ -147,29 +102,6 @@
}
/**
- * Test OnTimeStarted
- */
- @SmallTest
- public void testOnTimeStarted() throws Exception {
- MockBatteryStatsImpl bsi = new MockBatteryStatsImpl();
- TestServ serv = new TestServ(bsi);
-
- serv.populate();
- serv.setRunning(true);
- serv.onTimeStarted(111111, 20000, 222222);
- Assert.assertEquals(18989, serv.getUnpluggedStartTime());
- Assert.assertEquals(4042, serv.getUnpluggedStarts());
- Assert.assertEquals(8085, serv.getUnpluggedLaunches());
-
- serv.populate();
- serv.setRunning(false);
- serv.onTimeStarted(111111, 20000, 222222);
- Assert.assertEquals(1010, serv.getUnpluggedStartTime());
- Assert.assertEquals(4042, serv.getUnpluggedStarts());
- Assert.assertEquals(8085, serv.getUnpluggedLaunches());
- }
-
- /**
* Test parceling and unparceling.
*/
@SmallTest
@@ -185,7 +117,7 @@
TestServ serv = new TestServ(bsi);
serv.readFromParcelLocked(parcel);
-
+
Assert.assertEquals(1010, serv.getStartTime());
Assert.assertEquals(2021, serv.getRunningSince());
Assert.assertTrue(serv.getRunning());
@@ -194,15 +126,8 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(0, serv.getLastStartTime());
- Assert.assertEquals(0, serv.getLastStarts());
- Assert.assertEquals(0, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+
+ parcel.recycle();
}
/**
@@ -267,15 +192,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -303,15 +219,6 @@
Assert.assertEquals(777777L, serv.getLaunchedSince()); // <-- changed
Assert.assertTrue(serv.getLaunched()); // <-- changed
Assert.assertEquals(8086, serv.getLaunches()); // <-- changed
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -341,15 +248,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertFalse(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -375,19 +273,10 @@
Assert.assertEquals(2021, serv.getRunningSince());
Assert.assertTrue(serv.getRunning());
Assert.assertEquals(4042, serv.getStarts());
- Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed
+ Assert.assertEquals(777777L-6064+5053, serv.getLaunchedTime()); // <-- changed
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertFalse(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -416,16 +305,7 @@
Assert.assertEquals(5053, serv.getLaunchedTime());
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertFalse(serv.getLaunched());
- Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
+ Assert.assertEquals(8085-1, serv.getLaunches()); // <-- changed
}
/**
@@ -455,15 +335,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -492,15 +363,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -530,15 +392,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -568,15 +421,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -600,8 +444,6 @@
serv.populate();
Assert.assertEquals(8085, serv.getLaunches(BatteryStats.STATS_SINCE_CHARGED));
- Assert.assertEquals(8085-11118, serv.getLaunches(BatteryStats.STATS_CURRENT));
- Assert.assertEquals(8085-17714, serv.getLaunches(BatteryStats.STATS_SINCE_UNPLUGGED));
// No change to fields
Assert.assertEquals(1010, serv.getStartTime());
@@ -612,15 +454,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -637,10 +470,6 @@
Assert.assertEquals(startTimeToNow,
serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
- Assert.assertEquals(startTimeToNow-9096,
- serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
- Assert.assertEquals(startTimeToNow-15512,
- serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
// No change to fields
Assert.assertEquals(1010, serv.getStartTime());
@@ -651,15 +480,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
/**
@@ -676,10 +496,6 @@
Assert.assertEquals(startTimeToNow,
serv.getStartTime(20000, BatteryStats.STATS_SINCE_CHARGED));
- Assert.assertEquals(startTimeToNow-9096,
- serv.getStartTime(20000, BatteryStats.STATS_CURRENT));
- Assert.assertEquals(startTimeToNow-15512,
- serv.getStartTime(20000, BatteryStats.STATS_SINCE_UNPLUGGED));
// No change to fields
Assert.assertEquals(1010, serv.getStartTime());
@@ -690,15 +506,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
@@ -712,8 +519,6 @@
serv.populate();
Assert.assertEquals(4042, serv.getStarts(BatteryStats.STATS_SINCE_CHARGED));
- Assert.assertEquals(4042-10017, serv.getStarts(BatteryStats.STATS_CURRENT));
- Assert.assertEquals(4042-16613, serv.getStarts(BatteryStats.STATS_SINCE_UNPLUGGED));
// No change to fields
Assert.assertEquals(1010, serv.getStartTime());
@@ -724,15 +529,6 @@
Assert.assertEquals(6064, serv.getLaunchedSince());
Assert.assertTrue(serv.getLaunched());
Assert.assertEquals(8085, serv.getLaunches());
- Assert.assertEquals(9096, serv.getLoadedStartTime());
- Assert.assertEquals(10017, serv.getLoadedStarts());
- Assert.assertEquals(11118, serv.getLoadedLaunches());
- Assert.assertEquals(12219, serv.getLastStartTime());
- Assert.assertEquals(13310, serv.getLastStarts());
- Assert.assertEquals(14411, serv.getLastLaunches());
- Assert.assertEquals(15512, serv.getUnpluggedStartTime());
- Assert.assertEquals(16613, serv.getUnpluggedStarts());
- Assert.assertEquals(17714, serv.getUnpluggedLaunches());
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
index bce8b40..e5441c0 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimeBaseTest.java
@@ -282,12 +282,6 @@
Assert.assertEquals(100+300+666-400,
tb.computeUptime(666, BatteryStats.STATS_SINCE_CHARGED));
- Assert.assertEquals(300+666-400,
- tb.computeUptime(666, BatteryStats.STATS_CURRENT));
- Assert.assertEquals(300+666-400-50,
- tb.computeUptime(666, BatteryStats.STATS_SINCE_UNPLUGGED));
-
- Assert.assertEquals(0, tb.computeUptime(666, 6000));
}
/**
@@ -301,12 +295,6 @@
Assert.assertEquals(200+500+6666-600,
tb.computeRealtime(6666, BatteryStats.STATS_SINCE_CHARGED));
- Assert.assertEquals(500+6666-600,
- tb.computeRealtime(6666, BatteryStats.STATS_CURRENT));
- Assert.assertEquals(500+6666-600-60,
- tb.computeRealtime(6666, BatteryStats.STATS_SINCE_UNPLUGGED));
-
- Assert.assertEquals(0, tb.computeUptime(666, 6000));
}
/**
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
index 87dc2f3..40e3a5f 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsTimerTest.java
@@ -66,30 +66,6 @@
mCount = val;
}
- public int getLoadedCount() {
- return mLoadedCount;
- }
-
- public void setLoadedCount(int val) {
- mLoadedCount = val;
- }
-
- public int getLastCount() {
- return mLastCount;
- }
-
- public void setLastCount(int val) {
- mLastCount = val;
- }
-
- public int getUnpluggedCount() {
- return mUnpluggedCount;
- }
-
- public void setUnpluggedCount(int val) {
- mUnpluggedCount = val;
- }
-
public long getTotalTime() {
return mTotalTime;
}
@@ -98,30 +74,6 @@
mTotalTime = val;
}
- public long getLoadedTime() {
- return mLoadedTime;
- }
-
- public void setLoadedTime(long val) {
- mLoadedTime = val;
- }
-
- public long getLastTime() {
- return mLastTime;
- }
-
- public void setLastTime(long val) {
- mLastTime = val;
- }
-
- public long getUnpluggedTime() {
- return mUnpluggedTime;
- }
-
- public void setUnpluggedTime(long val) {
- mUnpluggedTime = val;
- }
-
public long getTimeBeforeMark() {
return mTimeBeforeMark;
}
@@ -143,16 +95,12 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.nextComputeCurrentCount = 3000;
- // Test that starting the timer counts the unplugged time and counters
+ // Test that stopping the timer updates mTotalTime and mCount
timer.nextComputeRunTime = 4;
timer.onTimeStarted(10, 20, 50);
- Assert.assertEquals(50, timer.lastComputeRunTimeRealtime);
- Assert.assertEquals(4, timer.getUnpluggedTime());
- Assert.assertEquals(3000, timer.getUnpluggedCount());
-
- // Test that stopping the timer updates mTotalTime and mCount
timer.nextComputeRunTime = 17;
timer.onTimeStopped(100, 130, 170);
+ Assert.assertEquals(170, timer.lastComputeRunTimeRealtime);
Assert.assertEquals(17, timer.getTotalTime());
Assert.assertEquals(3000, timer.getCount());
}
@@ -168,13 +116,7 @@
// Test write then read
TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
timer1.setCount(1);
- timer1.setLoadedCount(3);
- timer1.setLastCount(4);
- timer1.setUnpluggedCount(5);
timer1.setTotalTime(9223372036854775807L);
- timer1.setLoadedTime(9223372036854775806L);
- timer1.setLastTime(9223372036854775805L);
- timer1.setUnpluggedTime(9223372036854775804L);
timer1.setTimeBeforeMark(9223372036854775803L);
timer1.nextComputeRunTime = 201;
timer1.nextComputeCurrentCount = 2;
@@ -187,13 +129,7 @@
TestTimer timer2 = new TestTimer(clocks, 0, timeBase, parcel);
Assert.assertEquals(2, timer2.getCount()); // from computeTotalCountLocked()
- Assert.assertEquals(3, timer2.getLoadedCount());
- Assert.assertEquals(0, timer2.getLastCount()); // NOT saved
- Assert.assertEquals(5, timer2.getUnpluggedCount());
Assert.assertEquals(201, timer2.getTotalTime()); // from computeRunTimeLocked()
- Assert.assertEquals(9223372036854775806L, timer2.getLoadedTime());
- Assert.assertEquals(0, timer2.getLastTime()); // NOT saved
- Assert.assertEquals(9223372036854775804L, timer2.getUnpluggedTime());
Assert.assertEquals(9223372036854775803L, timer2.getTimeBeforeMark());
parcel.recycle();
@@ -224,25 +160,13 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
- timer.setLoadedCount(2);
- timer.setLastCount(3);
- timer.setUnpluggedCount(4);
timer.setTotalTime(9223372036854775807L);
- timer.setLoadedTime(9223372036854775806L);
- timer.setLastTime(9223372036854775805L);
- timer.setUnpluggedTime(9223372036854775804L);
timer.setTimeBeforeMark(9223372036854775803L);
timer.reset(false);
Assert.assertEquals(0, timer.getCount());
- Assert.assertEquals(0, timer.getLoadedCount());
- Assert.assertEquals(0, timer.getLastCount());
- Assert.assertEquals(4, timer.getUnpluggedCount());
Assert.assertEquals(0, timer.getTotalTime());
- Assert.assertEquals(0, timer.getLoadedTime());
- Assert.assertEquals(0, timer.getLastTime());
- Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
Assert.assertEquals(0, timer.getTimeBeforeMark());
// reset(false) shouldn't remove it from the list
@@ -259,25 +183,13 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
- timer.setLoadedCount(2);
- timer.setLastCount(3);
- timer.setUnpluggedCount(4);
timer.setTotalTime(9223372036854775807L);
- timer.setLoadedTime(9223372036854775806L);
- timer.setLastTime(9223372036854775805L);
- timer.setUnpluggedTime(9223372036854775804L);
timer.setTimeBeforeMark(9223372036854775803L);
timer.reset(true);
Assert.assertEquals(0, timer.getCount());
- Assert.assertEquals(0, timer.getLoadedCount());
- Assert.assertEquals(0, timer.getLastCount());
- Assert.assertEquals(4, timer.getUnpluggedCount());
Assert.assertEquals(0, timer.getTotalTime());
- Assert.assertEquals(0, timer.getLoadedTime());
- Assert.assertEquals(0, timer.getLastTime());
- Assert.assertEquals(9223372036854775804L, timer.getUnpluggedTime());
Assert.assertEquals(0, timer.getTimeBeforeMark());
// reset(true) should remove it from the list
@@ -299,13 +211,7 @@
TestTimer timer1 = new TestTimer(clocks, 0, timeBase);
timer1.setCount(1);
- timer1.setLoadedCount(2);
- timer1.setLastCount(3);
- timer1.setUnpluggedCount(4);
timer1.setTotalTime(9223372036854775807L);
- timer1.setLoadedTime(9223372036854775806L);
- timer1.setLastTime(9223372036854775805L);
- timer1.setUnpluggedTime(9223372036854775804L);
timer1.setTimeBeforeMark(9223372036854775803L);
Parcel parcel = Parcel.obtain();
@@ -318,13 +224,7 @@
// Make sure that all the values get touched
timer2.setCount(666);
- timer2.setLoadedCount(666);
- timer2.setLastCount(666);
- timer2.setUnpluggedCount(666);
timer2.setTotalTime(666);
- timer2.setLoadedTime(666);
- timer2.setLastTime(666);
- timer2.setUnpluggedTime(666);
timer2.setTimeBeforeMark(666);
parcel.setDataPosition(0);
@@ -333,13 +233,7 @@
timer2.readSummaryFromParcelLocked(parcel);
Assert.assertEquals(1, timer2.getCount());
- Assert.assertEquals(1, timer2.getLoadedCount());
- Assert.assertEquals(0, timer2.getLastCount());
- Assert.assertEquals(1, timer2.getUnpluggedCount());
Assert.assertEquals(9223372036854775800L, timer2.getTotalTime());
- Assert.assertEquals(9223372036854775800L, timer2.getLoadedTime());
- Assert.assertEquals(0, timer2.getLastTime());
- Assert.assertEquals(9223372036854775800L, timer2.getUnpluggedTime());
Assert.assertEquals(9223372036854775800L, timer2.getTimeBeforeMark());
parcel.recycle();
@@ -359,32 +253,15 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
- timer.setLoadedCount(2);
- timer.setLastCount(3);
- timer.setUnpluggedCount(4);
timer.setTotalTime(100);
- timer.setLoadedTime(200);
- timer.setLastTime(300);
- timer.setUnpluggedTime(400);
timer.setTimeBeforeMark(500);
timer.nextComputeRunTime = 10000;
- // Timer.getTotalTimeLocked(STATS_SINCE_CHARGED)
timer.lastComputeRunTimeRealtime = -1;
Assert.assertEquals(10000,
timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_CHARGED));
Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
-
- // Timer.getTotalTimeLocked(STATS_CURRENT)
- timer.lastComputeRunTimeRealtime = -1;
- Assert.assertEquals(9800, timer.getTotalTimeLocked(66, BatteryStats.STATS_CURRENT));
- Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
-
- // Timer.getTotalTimeLocked(STATS_SINCE_UNPLUGGED)
- timer.lastComputeRunTimeRealtime = -1;
- Assert.assertEquals(9600, timer.getTotalTimeLocked(66, BatteryStats.STATS_SINCE_UNPLUGGED));
- Assert.assertEquals(40, timer.lastComputeRunTimeRealtime);
}
/**
@@ -401,26 +278,11 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
- timer.setLoadedCount(2);
- timer.setLastCount(3);
- timer.setUnpluggedCount(4);
timer.setTotalTime(100);
- timer.setLoadedTime(200);
- timer.setLastTime(300);
- timer.setUnpluggedTime(400);
timer.setTimeBeforeMark(500);
- // Timer.getCountLocked(STATS_SINCE_CHARGED)
timer.nextComputeCurrentCount = 10000;
Assert.assertEquals(10000, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
-
- // Timer.getCountLocked(STATS_CURRENT)
- timer.nextComputeCurrentCount = 10000;
- Assert.assertEquals(9998, timer.getCountLocked(BatteryStats.STATS_CURRENT));
-
- // Timer.getCountLocked(STATS_SINCE_UNPLUGGED)
- timer.nextComputeCurrentCount = 10000;
- Assert.assertEquals(9996, timer.getCountLocked(BatteryStats.STATS_SINCE_UNPLUGGED));
}
/**
@@ -437,13 +299,7 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setCount(1);
- timer.setLoadedCount(2);
- timer.setLastCount(3);
- timer.setUnpluggedCount(4);
timer.setTotalTime(100);
- timer.setLoadedTime(200);
- timer.setLastTime(300);
- timer.setUnpluggedTime(400);
timer.setTimeBeforeMark(500);
timer.nextComputeRunTime = 10000;
@@ -460,30 +316,16 @@
TestTimer timer = new TestTimer(clocks, 0, timeBase);
timer.setTotalTime(100);
- timer.setLoadedTime(200);
- timer.setLastTime(300);
- timer.setUnpluggedTime(400);
timer.setTimeBeforeMark(500);
timer.setCount(1);
- timer.setLoadedCount(2);
- timer.setLastCount(3);
- timer.setUnpluggedCount(4);
timer.setTotalTime(9223372036854775807L);
- timer.setLoadedTime(9223372036854775806L);
- timer.setLastTime(9223372036854775805L);
- timer.setUnpluggedTime(9223372036854775804L);
timer.setTimeBeforeMark(9223372036854775803L);
StringBuilder sb = new StringBuilder();
StringBuilderPrinter pw = new StringBuilderPrinter(sb);
timer.logState(pw, " ");
-
- Assert.assertEquals(
- " mCount=1 mLoadedCount=2 mLastCount=3 mUnpluggedCount=4\n"
- + " mTotalTime=9223372036854775807 mLoadedTime=9223372036854775806\n"
- + " mLastTime=9223372036854775805 mUnpluggedTime=9223372036854775804\n",
- sb.toString());
+ Assert.assertEquals(" mCount=1\n mTotalTime=9223372036854775807\n", sb.toString());
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
index 0516bb7..ee5d2d6 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
@@ -16,14 +16,12 @@
package com.android.internal.os;
-import static android.os.BatteryStats.STATS_CURRENT;
import static android.os.BatteryStats.STATS_SINCE_CHARGED;
-import static android.os.BatteryStats.STATS_SINCE_UNPLUGGED;
import static com.android.internal.os.BatteryStatsImpl.LongSamplingCounterArray;
import static com.android.internal.os.BatteryStatsImpl.TimeBase;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -41,8 +39,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.Arrays;
-
/**
* Test class for {@link BatteryStatsImpl.LongSamplingCounterArray}.
*
@@ -57,14 +53,15 @@
* ${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreTests/FrameworksCoreTests.apk
* Run: adb shell am instrument -e class com.android.internal.os.LongSamplingCounterArrayTest -w \
* com.android.frameworks.coretests/androidx.test.runner.AndroidJUnitRunner
+ *
+ * or just do
+ * atest frameworks/base/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterArrayTest.java
*/
@SmallTest
@RunWith(AndroidJUnit4.class)
public class LongSamplingCounterArrayTest {
private static final long[] COUNTS = {1111, 2222, 3333, 4444};
- private static final long[] LOADED_COUNTS = {5555, 6666, 7777, 8888};
- private static final long[] UNPLUGGED_COUNTS = {44444, 55555, 66666, 77777};
private static final long[] ZEROES = {0, 0, 0, 0};
@Mock private TimeBase mTimeBase;
@@ -80,75 +77,54 @@
@Test
public void testReadWriteParcel() {
final Parcel parcel = Parcel.obtain();
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
LongSamplingCounterArray.writeToParcel(parcel, mCounterArray);
parcel.setDataPosition(0);
// Now clear counterArray and verify values are read from parcel correctly.
- updateCounts(null, null, null);
+ updateCounts(null);
mCounterArray = LongSamplingCounterArray.readFromParcel(parcel, mTimeBase);
- assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
- "Unexpected unpluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mCounts);
parcel.recycle();
}
@Test
public void testReadWriteSummaryParcel() {
final Parcel parcel = Parcel.obtain();
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
LongSamplingCounterArray.writeSummaryToParcelLocked(parcel, mCounterArray);
parcel.setDataPosition(0);
// Now clear counterArray and verify values are read from parcel correctly.
- updateCounts(null, null, null);
+ updateCounts(null);
mCounterArray = LongSamplingCounterArray.readSummaryFromParcelLocked(parcel, mTimeBase);
- assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(COUNTS, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mCounts);
parcel.recycle();
}
@Test
public void testOnTimeStarted() {
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
mCounterArray.onTimeStarted(0, 0, 0);
- assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(COUNTS, mCounterArray.mUnpluggedCounts,
- "Unexpected unpluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mCounts);
}
@Test
public void testOnTimeStopped() {
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
mCounterArray.onTimeStopped(0, 0, 0);
- assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
- "Unexpected unpluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mCounts);
}
@Test
public void testGetCountsLocked() {
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
when(mTimeBase.isRunning()).thenReturn(false);
- assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED),
- "Unexpected values");
- assertArrayEquals(subtract(COUNTS, LOADED_COUNTS),
- mCounterArray.getCountsLocked(STATS_CURRENT), "Unexpected values");
- assertArrayEquals(subtract(COUNTS, UNPLUGGED_COUNTS),
- mCounterArray.getCountsLocked(STATS_SINCE_UNPLUGGED), "Unexpected values");
+ assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED));
when(mTimeBase.isRunning()).thenReturn(true);
- assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED),
- "Unexpected values");
- assertArrayEquals(subtract(COUNTS, LOADED_COUNTS),
- mCounterArray.getCountsLocked(STATS_CURRENT), "Unexpected values");
- assertArrayEquals(subtract(COUNTS, UNPLUGGED_COUNTS),
- mCounterArray.getCountsLocked(STATS_SINCE_UNPLUGGED), "Unexpected values");
+ assertArrayEquals(COUNTS, mCounterArray.getCountsLocked(STATS_SINCE_CHARGED));
}
private long[] subtract(long[] val, long[] toSubtract) {
@@ -163,64 +139,45 @@
@Test
public void testAddCountLocked() {
- updateCounts(null, null, null);
+ updateCounts(null);
final long[] deltas = {123, 234, 345, 456};
when(mTimeBase.isRunning()).thenReturn(true);
mCounterArray.addCountLocked(deltas);
- assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ assertArrayEquals(deltas, mCounterArray.mCounts);
- updateCounts(null, null, null);
+ updateCounts(null);
mCounterArray.addCountLocked(deltas, false);
- assertArrayEquals(null, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ assertArrayEquals(null, mCounterArray.mCounts);
mCounterArray.addCountLocked(deltas, true);
- assertArrayEquals(deltas, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(null, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(null, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ assertArrayEquals(deltas, mCounterArray.mCounts);
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
final long[] newCounts = new long[deltas.length];
for (int i = 0; i < deltas.length; ++i) {
newCounts[i] = COUNTS[i] + deltas[i];
}
mCounterArray.addCountLocked(deltas);
- assertArrayEquals(newCounts, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
- "Unexpected unpluggedCounts");
+ assertArrayEquals(newCounts, mCounterArray.mCounts);
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
mCounterArray.addCountLocked(deltas, false);
- assertArrayEquals(COUNTS, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
- "Unexpected unpluggedCounts");
+ assertArrayEquals(COUNTS, mCounterArray.mCounts);
mCounterArray.addCountLocked(deltas, true);
- assertArrayEquals(newCounts, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(LOADED_COUNTS, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(UNPLUGGED_COUNTS, mCounterArray.mUnpluggedCounts,
- "Unexpected unpluggedCounts");
+ assertArrayEquals(newCounts, mCounterArray.mCounts);
}
@Test
public void testReset() {
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
// Test with detachIfReset=false
mCounterArray.reset(false /* detachIfReset */);
- assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mCounts);
verifyZeroInteractions(mTimeBase);
- initializeCounterArrayWithDefaultValues();
+ updateCounts(COUNTS);
// Test with detachIfReset=true
mCounterArray.reset(true /* detachIfReset */);
- assertArrayEquals(ZEROES, mCounterArray.mCounts, "Unexpected counts");
- assertArrayEquals(ZEROES, mCounterArray.mLoadedCounts, "Unexpected loadedCounts");
- assertArrayEquals(ZEROES, mCounterArray.mUnpluggedCounts, "Unexpected unpluggedCounts");
+ assertArrayEquals(ZEROES, mCounterArray.mCounts);
verify(mTimeBase).remove(mCounterArray);
verifyNoMoreInteractions(mTimeBase);
}
@@ -232,18 +189,7 @@
verifyNoMoreInteractions(mTimeBase);
}
- private void initializeCounterArrayWithDefaultValues() {
- updateCounts(COUNTS, LOADED_COUNTS, UNPLUGGED_COUNTS);
- }
-
- private void assertArrayEquals(long[] expected, long[] actual, String msg) {
- assertTrue(msg + ", expected: " + Arrays.toString(expected)
- + ", actual: " + Arrays.toString(actual), Arrays.equals(expected, actual));
- }
-
- private void updateCounts(long[] counts, long[] loadedCounts, long[] unpluggedCounts) {
+ private void updateCounts(long[] counts) {
mCounterArray.mCounts = counts == null ? null : counts.clone();
- mCounterArray.mLoadedCounts = loadedCounts == null ? null : loadedCounts.clone();
- mCounterArray.mUnpluggedCounts = unpluggedCounts == null ? null : unpluggedCounts.clone();
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
index d2f5735..dccc3d3 100644
--- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java
@@ -51,7 +51,6 @@
public class LongSamplingCounterTest {
private static final long COUNT = 1111;
- private static final long CURRENT_COUNT = 5555;
@Mock
private TimeBase mTimeBase;
@@ -67,116 +66,87 @@
@Test
public void testReadWriteParcel() {
final Parcel parcel = Parcel.obtain();
- updateCounts(COUNT, CURRENT_COUNT);
+ mCounter.addCountLocked(COUNT, true);
+ assertEquals(COUNT, getCount());
mCounter.writeToParcel(parcel);
parcel.setDataPosition(0);
- // Now clear counterArray and verify values are read from parcel correctly.
- updateCounts(0, 0);
+ // Now change count but verify values are read from parcel correctly.
+ mCounter.addCountLocked(7 * COUNT, true);
+ assertEquals(8 * COUNT, getCount());
mCounter = new LongSamplingCounter(mTimeBase, parcel);
- assertEquals(COUNT, mCounter.mCount);
- assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+ assertEquals(COUNT, getCount());
parcel.recycle();
}
@Test
public void testReadWriteSummaryParcel() {
final Parcel parcel = Parcel.obtain();
- updateCounts(COUNT, CURRENT_COUNT);
+ mCounter.addCountLocked(COUNT, true);
+ assertEquals(COUNT, getCount());
mCounter.writeSummaryFromParcelLocked(parcel);
parcel.setDataPosition(0);
- // Now clear counterArray and verify values are read from parcel correctly.
- updateCounts(0, 0);
+ // Now change count but verify values are read from parcel correctly.
+ mCounter.addCountLocked(7 * COUNT, true);
+ assertEquals(8 * COUNT, getCount());
mCounter.readSummaryFromParcelLocked(parcel);
- assertEquals(COUNT, mCounter.mCount);
+ assertEquals(COUNT, getCount());
parcel.recycle();
}
@Test
public void testOnTimeStarted() {
- updateCounts(COUNT, CURRENT_COUNT);
+ mCounter.addCountLocked(COUNT, true);
+ assertEquals(COUNT, getCount());
mCounter.onTimeStarted(0, 0, 0);
- assertEquals(COUNT, mCounter.mCount);
- assertEquals(COUNT, mCounter.mUnpluggedCount);
+ assertEquals(COUNT, getCount());
}
@Test
public void testOnTimeStopped() {
- updateCounts(COUNT, CURRENT_COUNT);
+ mCounter.addCountLocked(COUNT, true);
+ assertEquals(COUNT, getCount());
mCounter.onTimeStopped(0, 0, 0);
- assertEquals(COUNT, mCounter.mCount);
+ assertEquals(COUNT, getCount());
}
@Test
public void testAddCountLocked() {
- updateCounts(0, 0);
- assertEquals(0, mCounter.getCountLocked(0));
+ assertEquals(0, getCount());
when(mTimeBase.isRunning()).thenReturn(true);
mCounter.addCountLocked(111);
assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(111, mCounter.mCurrentCount);
mCounter.addCountLocked(222);
assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(333, mCounter.mCurrentCount);
when(mTimeBase.isRunning()).thenReturn(false);
mCounter.addCountLocked(456);
assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(789, mCounter.mCurrentCount);
mCounter.addCountLocked(444, true);
assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(1233, mCounter.mCurrentCount);
mCounter.addCountLocked(567, false);
assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(1800, mCounter.mCurrentCount);
}
- @Test
- public void testUpdate() {
- updateCounts(0, 0);
- assertEquals(0, mCounter.getCountLocked(0));
- when(mTimeBase.isRunning()).thenReturn(true);
- mCounter.update(111);
- assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(111, mCounter.mCurrentCount);
- mCounter.update(333);
- assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(333, mCounter.mCurrentCount);
-
- when(mTimeBase.isRunning()).thenReturn(false);
- mCounter.update(789);
- assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(789, mCounter.mCurrentCount);
- mCounter.update(100);
- assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(100, mCounter.mCurrentCount);
-
- mCounter.update(544, true);
- assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(544, mCounter.mCurrentCount);
- mCounter.update(1544, false);
- assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED));
- assertEquals(1544, mCounter.mCurrentCount);
- }
@Test
public void testReset() {
- updateCounts(COUNT, CURRENT_COUNT);
+ mCounter.addCountLocked(COUNT, true);
+ assertEquals(COUNT, getCount());
// Test with detachIfReset=false
mCounter.reset(false /* detachIfReset */);
- assertEquals(0, mCounter.mCount);
- assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+ assertEquals(0, getCount());
verifyZeroInteractions(mTimeBase);
- updateCounts(COUNT, CURRENT_COUNT);
+ mCounter.addCountLocked(COUNT, true);
+ assertEquals(COUNT, getCount());
// Test with detachIfReset=true
mCounter.reset(true /* detachIfReset */);
- assertEquals(0, mCounter.mCount);
- assertEquals(CURRENT_COUNT, mCounter.mCurrentCount);
+ assertEquals(0, getCount());
verify(mTimeBase).remove(mCounter);
verifyNoMoreInteractions(mTimeBase);
}
@@ -188,8 +158,7 @@
verifyNoMoreInteractions(mTimeBase);
}
- private void updateCounts(long total, long current) {
- mCounter.mCount = total;
- mCounter.mCurrentCount = current;
+ private long getCount() {
+ return mCounter.getCountLocked(STATS_SINCE_CHARGED);
}
}
diff --git a/core/tests/overlaytests/device/assets/package-name.txt b/core/tests/overlaytests/device/assets/package-name.txt
new file mode 100644
index 0000000..8094438
--- /dev/null
+++ b/core/tests/overlaytests/device/assets/package-name.txt
@@ -0,0 +1 @@
+com.android.overlaytest
diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
index 91fcdbb..f86743a 100644
--- a/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
+++ b/core/tests/overlaytests/device/src/com/android/overlaytest/OverlayBaseTest.java
@@ -17,9 +17,12 @@
package com.android.overlaytest;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.UiAutomation;
+import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
@@ -30,6 +33,8 @@
import androidx.test.InstrumentationRegistry;
+import com.android.internal.util.ArrayUtils;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -291,6 +296,33 @@
assertEquals(getExpected(no, so, mo), actual);
}
+ @Test
+ public void testAssetsNotPossibleToOverlay() throws Throwable {
+ final AssetManager am = mResources.getAssets();
+
+ // AssetManager#list will include assets from all loaded non-overlay
+ // APKs, including the framework; framework-res.apk contains at least
+ // assets/{images,webkit}. Rather than checking the list, verify that
+ // assets only present in overlays are never part of the list.
+ String[] files = am.list("");
+ assertTrue(ArrayUtils.contains(files, "package-name.txt"));
+ assertFalse(ArrayUtils.contains(files, "foo.txt"));
+ assertFalse(ArrayUtils.contains(files, "bar.txt"));
+
+ String contents = null;
+ try (InputStream is = am.open("package-name.txt")) {
+ final BufferedReader reader = new BufferedReader(
+ new InputStreamReader(is, StandardCharsets.UTF_8));
+ StringBuilder str = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ str.append(line);
+ }
+ contents = str.toString();
+ }
+ assertEquals("com.android.overlaytest", contents);
+ }
+
/*
* testMatrix* tests
*
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
index 1719158..8ac6953 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
@@ -18,5 +18,6 @@
package="com.android.overlaytest.app_overlay_one"
android:versionCode="1"
android:versionName="1.0">
+ <application android:hasCode="false" />
<overlay android:targetPackage="com.android.overlaytest" android:priority="1" />
</manifest>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/foo.txt
@@ -0,0 +1 @@
+foo
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt
new file mode 100644
index 0000000..087cb96
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/assets/package-name.txt
@@ -0,0 +1 @@
+com.android.overlaytest.app_overlay_one
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
index ae8307c..f3c39cc 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
@@ -18,5 +18,6 @@
package="com.android.overlaytest.app_overlay_two"
android:versionCode="1"
android:versionName="1.0">
+ <application android:hasCode="false" />
<overlay android:targetPackage="com.android.overlaytest" android:priority="2" />
</manifest>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/bar.txt
@@ -0,0 +1 @@
+bar
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt
new file mode 100644
index 0000000..1318565
--- /dev/null
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/assets/package-name.txt
@@ -0,0 +1 @@
+com.android.overlaytest.app_overlay_two
diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
index 77ea16a..73a83e0 100644
--- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/AndroidManifest.xml
@@ -18,5 +18,6 @@
package="com.android.overlaytest.framework"
android:versionCode="1"
android:versionName="1.0">
+ <application android:hasCode="false" />
<overlay android:targetPackage="android" android:priority="1" />
</manifest>
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index 27986cc..f9672d2 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -155,12 +155,26 @@
}
}
+ private void delay() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ private void installPackage(String pkg) throws Exception {
+ super.installPackage(pkg);
+ delay();
+ }
+
private void setPackageEnabled(String pkg, boolean enabled) throws Exception {
getDevice().executeShellCommand("cmd package " + (enabled ? "enable " : "disable ") + pkg);
+ delay();
}
private void setOverlayEnabled(String pkg, boolean enabled) throws Exception {
getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
+ delay();
}
private boolean overlayManagerContainsPackage(String pkg) throws Exception {
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
index b08ac96..26b3875 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
@@ -16,5 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.signature_overlay">
+ <application android:hasCode="false" />
<overlay android:targetPackage="android" />
</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml
index 139dd96..8a66423 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/static/AndroidManifest.xml
@@ -16,5 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.signature_overlay">
+ <application android:hasCode="false" />
<overlay android:targetPackage="android" android:isStatic="true" />
</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
index 73804eb..b6ff0c3 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/AndroidManifest.xml
@@ -16,5 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.app_overlay">
+ <application android:hasCode="false" />
<overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" />
</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
index 9ec7d06..f1a3981 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.app_overlay">
+ <application android:hasCode="false" />
<overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test"
android:category="android.theme" />
</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
index 8c8fe94..025d1a2 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
@@ -16,5 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.framework_overlay">
+ <application android:hasCode="false" />
<overlay android:targetPackage="android" />
</manifest>
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 44d71e2..28d311e 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -202,17 +202,15 @@
<new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</split-permission>
- <!-- Apps holding either the legacy READ or WRITE permissions will inherit
- the ability to <em>read</em> new typed permissions in the Q release; they
- won't gain the ability to <em>write</em> that content. -->
- <!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised -->
+ <!-- STOPSHIP: change targetSdk to Q when SDK version finalised -->
+ <!-- Old apps might not understand the modern permission model, hence their view needs to be expanded -->
<split-permission name="android.permission.READ_EXTERNAL_STORAGE"
targetSdk="10000">
<new-permission name="android.permission.READ_MEDIA_AUDIO" />
<new-permission name="android.permission.READ_MEDIA_VIDEO" />
<new-permission name="android.permission.READ_MEDIA_IMAGES" />
</split-permission>
- <!-- STOPSHIP(b/112545973): change targetSdk to Q when SDK version finalised -->
+ <!-- STOPSHIP: change targetSdk to Q when SDK version finalised -->
<split-permission name="android.permission.WRITE_EXTERNAL_STORAGE"
targetSdk="10000">
<new-permission name="android.permission.READ_MEDIA_AUDIO" />
@@ -220,6 +218,20 @@
<new-permission name="android.permission.READ_MEDIA_IMAGES" />
</split-permission>
+ <!-- An app using the typed media permissions might be grandfathered and then uses the old storage model -->
+ <split-permission name="android.permission.READ_MEDIA_AUDIO">
+ <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
+ <new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ </split-permission>
+ <split-permission name="android.permission.READ_MEDIA_VIDEO">
+ <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
+ <new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ </split-permission>
+ <split-permission name="android.permission.READ_MEDIA_IMAGES">
+ <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
+ <new-permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ </split-permission>
+
<!-- This is a list of all the libraries available for application
code to link against. -->
diff --git a/docs/html/reference/images/text/style/linebackgroundspan.png b/docs/html/reference/images/text/style/linebackgroundspan.png
new file mode 100644
index 0000000..37d5253
--- /dev/null
+++ b/docs/html/reference/images/text/style/linebackgroundspan.png
Binary files differ
diff --git a/docs/html/reference/images/text/style/lineheightspan.png b/docs/html/reference/images/text/style/lineheightspan.png
new file mode 100644
index 0000000..18f5753
--- /dev/null
+++ b/docs/html/reference/images/text/style/lineheightspan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 0d52338..9c4b5e8 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1809,6 +1809,45 @@
}
/**
+ * <p>Computes the chromaticity coordinates of a specified correlated color
+ * temperature (CCT) on the Planckian locus. The specified CCT must be
+ * greater than 0. A meaningful CCT range is [1667, 25000].</p>
+ *
+ * <p>The transform is computed using the methods in Kang et
+ * al., <i>Design of Advanced Color - Temperature Control System for HDTV
+ * Applications</i>, Journal of Korean Physical Society 41, 865-871
+ * (2002).</p>
+ *
+ * @param cct The correlated color temperature, in Kelvin
+ * @return Corresponding XYZ values
+ * @throws IllegalArgumentException If cct is invalid
+ *
+ * @hide
+ */
+ @NonNull
+ @Size(3)
+ public static float[] cctToXyz(@IntRange(from = 1) int cct) {
+ if (cct < 1) {
+ throw new IllegalArgumentException("Temperature must be greater than 0");
+ }
+
+ final float icct = 1e3f / cct;
+ final float icct2 = icct * icct;
+ final float x = cct <= 4000.0f ?
+ 0.179910f + 0.8776956f * icct - 0.2343589f * icct2 - 0.2661239f * icct2 * icct :
+ 0.240390f + 0.2226347f * icct + 2.1070379f * icct2 - 3.0258469f * icct2 * icct;
+
+ final float x2 = x * x;
+ final float y = cct <= 2222.0f ?
+ -0.20219683f + 2.18555832f * x - 1.34811020f * x2 - 1.1063814f * x2 * x :
+ cct <= 4000.0f ?
+ -0.16748867f + 2.09137015f * x - 1.37418593f * x2 - 0.9549476f * x2 * x :
+ -0.37001483f + 3.75112997f * x - 5.8733867f * x2 + 3.0817580f * x2 * x;
+
+ return xyYToXyz(new float[] {x, y});
+ }
+
+ /**
* <p>Computes the chromaticity coordinates of a CIE series D illuminant
* from the specified correlated color temperature (CCT). The specified CCT
* must be greater than 0. A meaningful CCT range is [4000, 25000].</p>
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 64f7591..c8b361b 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -38,7 +38,6 @@
import android.provider.FontsContract;
import android.text.FontConfig;
import android.util.Base64;
-import android.util.Log;
import android.util.LongSparseArray;
import android.util.LruCache;
import android.util.SparseArray;
@@ -262,30 +261,10 @@
? FontStyle.FONT_SLANT_ITALIC : FontStyle.FONT_SLANT_UPRIGHT);
}
- Font font = null;
- try {
- font = fontBuilder.build();
- } catch (IllegalArgumentException e) {
- // The exception happens if the unsupported font is passed. We suppress this
- // exception and just ignore this font here since there is no way of
- // resolving this issue by users during inflating layout.
- Log.w(TAG, "Ignoring font file since failed to create font object."
- + " The font file is not supported on this platform.");
- continue;
- }
if (familyBuilder == null) {
- familyBuilder = new FontFamily.Builder(font);
+ familyBuilder = new FontFamily.Builder(fontBuilder.build());
} else {
- try {
- familyBuilder.addFont(font);
- } catch (IllegalArgumentException e) {
- // The exception happens if the same style is added to the family.
- // We suppress this exception and just ignore this font here since there is
- // no way of resolving this issue by users during inflating layout.
- Log.w(TAG,
- "Ignoring font file since the same style font is already added.");
- continue;
- }
+ familyBuilder.addFont(fontBuilder.build());
}
}
if (familyBuilder == null) {
@@ -307,6 +286,10 @@
typeface = new Typeface.CustomFallbackBuilder(family)
.setStyle(bestFont.getStyle())
.build();
+ } catch (IllegalArgumentException e) {
+ // To be a compatible behavior with API28 or before, catch IllegalArgumentExcetpion
+ // thrown by native code and returns null.
+ return null;
} catch (IOException e) {
typeface = Typeface.DEFAULT;
}
diff --git a/graphics/java/android/graphics/fonts/Font.java b/graphics/java/android/graphics/fonts/Font.java
index b857465..552088f 100644
--- a/graphics/java/android/graphics/fonts/Font.java
+++ b/graphics/java/android/graphics/fonts/Font.java
@@ -354,10 +354,6 @@
/**
* Creates the font based on the configured values.
- *
- * If the font is not supported by the platform, this function will fail with
- * {@link IllegalArgumentException}.
- *
* @return the Font object
*/
public @NonNull Font build() throws IOException {
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index 66bcd865..9db7533 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -65,6 +65,7 @@
/**
* Returns the characters in the paragraph used to compute this MeasuredText instance.
+ * @hide
*/
public @NonNull char[] getChars() {
return mChars;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 105af6e8..51c4252 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,7 +16,6 @@
package android.security.keystore;
-import libcore.util.EmptyArray;
import android.security.Credentials;
import android.security.GateKeeper;
import android.security.KeyStore;
@@ -31,6 +30,8 @@
import android.security.keystore.WrappedKeyEntry;
import android.util.Log;
+import libcore.util.EmptyArray;
+
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -123,7 +124,14 @@
final Certificate[] caList;
- final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
+ // Suppress the key not found warning for this call. It seems that this error is exclusively
+ // being thrown when there is a self signed certificate chain, so when the keystore service
+ // attempts to query for the CA details, it obviously fails to find them and returns a
+ // key not found exception. This is WAI, and throwing a stack trace here can be very
+ // misleading since the trace is not clear.
+ final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
+ mUid,
+ true /* suppressKeyNotFoundWarning */);
if (caBytes != null) {
final Collection<X509Certificate> caChain = toCertificates(caBytes);
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index c512a6b..9a95fdf 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -292,8 +292,10 @@
pAsset = new _FileAsset;
result = pAsset->openChunk(dataMap);
- if (result != NO_ERROR)
+ if (result != NO_ERROR) {
+ delete pAsset;
return NULL;
+ }
pAsset->mAccessMode = mode;
return pAsset;
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index d74f27c..9519704 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -310,6 +310,9 @@
// Start from the back.
for (auto iter = apk_assets_.rbegin(); iter != apk_assets_.rend(); ++iter) {
const ApkAssets* apk_assets = *iter;
+ if (apk_assets->IsOverlay()) {
+ continue;
+ }
auto func = [&](const StringPiece& name, FileType type) {
AssetDir::FileInfo info;
@@ -336,6 +339,13 @@
Asset::AccessMode mode,
ApkAssetsCookie* out_cookie) const {
for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
+ // Prevent RRO from modifying assets and other entries accessed by file
+ // path. Explicitly asking for a path in a given package (denoted by a
+ // cookie) is still OK.
+ if (apk_assets_[i]->IsOverlay()) {
+ continue;
+ }
+
std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
if (asset) {
if (out_cookie != nullptr) {
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index db2d038..35bbb58 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -80,6 +80,10 @@
return loaded_arsc_.get();
}
+ inline bool IsOverlay() const {
+ return idmap_asset_.get() != nullptr;
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(ApkAssets);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 4f1b2a4..ebba4cb 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -191,7 +191,7 @@
"surfacetexture/EGLConsumer.cpp",
"surfacetexture/ImageConsumer.cpp",
"surfacetexture/SurfaceTexture.cpp",
- "thread/TaskManager.cpp",
+ "thread/CommonPool.cpp",
"utils/Blur.cpp",
"utils/Color.cpp",
"utils/GLUtils.cpp",
@@ -308,6 +308,7 @@
"tests/unit/main.cpp",
"tests/unit/CacheManagerTests.cpp",
"tests/unit/CanvasContextTests.cpp",
+ "tests/unit/CommonPoolTests.cpp",
"tests/unit/DamageAccumulatorTests.cpp",
"tests/unit/DeferredLayerUpdaterTests.cpp",
"tests/unit/FatVectorTests.cpp",
@@ -381,7 +382,6 @@
"tests/microbench/LinearAllocatorBench.cpp",
"tests/microbench/PathParserBench.cpp",
"tests/microbench/RenderNodeBench.cpp",
- "tests/microbench/TaskManagerBench.cpp",
],
}
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index b04c774..3a8e559 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -17,6 +17,7 @@
#include "IProfileRenderer.h"
#include "utils/Color.h"
+#include "utils/TimeUtils.h"
#include <cutils/compiler.h>
#include <array>
@@ -26,22 +27,24 @@
#define RETURN_IF_DISABLED() \
if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
-#define PROFILE_DRAW_WIDTH 3
-#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
-#define PROFILE_DRAW_DP_PER_MS 7
-
namespace android {
namespace uirenderer {
-// Must be NUM_ELEMENTS in size
-static const SkColor THRESHOLD_COLOR = Color::Green_500;
-static const SkColor BAR_FAST_MASK = 0x8FFFFFFF;
-static const SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
+static constexpr auto PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
+static constexpr auto PROFILE_DRAW_DP_PER_MS = 7;
-// We could get this from TimeLord and use the actual frame interval, but
-// this is good enough
-#define FRAME_THRESHOLD 16
-#define FRAME_THRESHOLD_NS 16000000
+struct Threshold {
+ SkColor color;
+ float percentFrametime;
+};
+
+static constexpr std::array<Threshold, 3> THRESHOLDS{
+ Threshold{.color = Color::Green_500, .percentFrametime = 0.8f},
+ Threshold{.color = Color::Lime_500, .percentFrametime = 1.0f},
+ Threshold{.color = Color::Red_500, .percentFrametime = 1.5f},
+};
+static constexpr SkColor BAR_FAST_MASK = 0x8FFFFFFF;
+static constexpr SkColor BAR_JANKY_MASK = 0xDFFFFFFF;
struct BarSegment {
FrameInfoIndex start;
@@ -64,7 +67,8 @@
return (int)(dp * density + 0.5f);
}
-FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
+FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval)
+ : mFrameSource(source), mFrameInterval(frameInterval) {
setDensity(1);
consumeProperties();
}
@@ -76,7 +80,10 @@
void FrameInfoVisualizer::setDensity(float density) {
if (CC_UNLIKELY(mDensity != density)) {
mDensity = density;
- mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
+ // We want the vertical units to scale height relative to a baseline 16ms.
+ // This keeps the threshold lines consistent across varying refresh rates
+ mVerticalUnit = static_cast<int>(dpToPx(PROFILE_DRAW_DP_PER_MS, density) * (float)16_ms /
+ (float)mFrameInterval);
mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
}
}
@@ -148,7 +155,7 @@
float* rect;
int ri;
// Rects are LTRB
- if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
+ if (mFrameSource[fi].totalDuration() <= mFrameInterval) {
rect = mFastRects.get();
ri = fast_i;
fast_i += 4;
@@ -181,7 +188,7 @@
float* rect;
int ri;
// Rects are LTRB
- if (mFrameSource[fi].totalDuration() <= FRAME_THRESHOLD_NS) {
+ if (mFrameSource[fi].totalDuration() <= mFrameInterval) {
rect = mFastRects.get();
ri = fast_i;
fast_i -= 4;
@@ -211,10 +218,13 @@
void FrameInfoVisualizer::drawThreshold(IProfileRenderer& renderer) {
SkPaint paint;
- paint.setColor(THRESHOLD_COLOR);
- float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
- renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
- yLocation + mThresholdStroke / 2, paint);
+ for (auto& t : THRESHOLDS) {
+ paint.setColor(t.color);
+ float yLocation = renderer.getViewportHeight() -
+ (ns2ms(mFrameInterval) * t.percentFrametime * mVerticalUnit);
+ renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
+ yLocation + mThresholdStroke / 2, paint);
+ }
}
bool FrameInfoVisualizer::consumeProperties() {
diff --git a/libs/hwui/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h
index b98f501..3040a77 100644
--- a/libs/hwui/FrameInfoVisualizer.h
+++ b/libs/hwui/FrameInfoVisualizer.h
@@ -39,7 +39,7 @@
class FrameInfoVisualizer {
public:
- explicit FrameInfoVisualizer(FrameInfoSource& source);
+ explicit FrameInfoVisualizer(FrameInfoSource& source, nsecs_t frameInterval);
~FrameInfoVisualizer();
bool consumeProperties();
@@ -71,6 +71,7 @@
FrameInfoSource& mFrameSource;
+ nsecs_t mFrameInterval;
int mVerticalUnit = 0;
int mThresholdStroke = 0;
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index aeeb32c..8f7e814 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -18,6 +18,7 @@
#include "hwui/Bitmap.h"
#include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
#include "thread/ThreadBase.h"
#include "utils/TimeUtils.h"
@@ -25,7 +26,9 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
+#include <GrContext.h>
#include <SkCanvas.h>
+#include <SkImage.h>
#include <utils/GLUtils.h>
#include <utils/Trace.h>
#include <utils/TraceUtils.h>
@@ -33,58 +36,247 @@
namespace android::uirenderer {
-static std::mutex sLock{};
-static sp<ThreadBase> sUploadThread = nullptr;
-static renderthread::EglManager sEglManager;
-static int sPendingUploads = 0;
-static nsecs_t sLastUpload = 0;
+class AHBUploader;
+// This helper uploader classes allows us to upload using either EGL or Vulkan using the same
+// interface.
+static sp<AHBUploader> sUploader = nullptr;
-static bool shouldTimeOutLocked() {
- nsecs_t durationSince = systemTime() - sLastUpload;
- return durationSince > 2000_ms;
-}
+struct FormatInfo {
+ PixelFormat pixelFormat;
+ GLint format, type;
+ VkFormat vkFormat;
+ bool isSupported = false;
+ bool valid = true;
+};
-static void checkIdleTimeout() {
- std::lock_guard _lock{sLock};
- if (sPendingUploads == 0 && shouldTimeOutLocked()) {
- sEglManager.destroy();
- } else {
- sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
- }
-}
+class AHBUploader : public RefBase {
+public:
+ virtual ~AHBUploader() {}
-static void beginUpload() {
- std::lock_guard _lock{sLock};
- sPendingUploads++;
-
- if (!sUploadThread) {
- sUploadThread = new ThreadBase{};
+ // Called to start creation of the Vulkan and EGL contexts on another thread before we actually
+ // need to do an upload.
+ void initialize() {
+ onInitialize();
}
- if (!sUploadThread->isRunning()) {
- sUploadThread->start("GrallocUploadThread");
+ void destroy() {
+ std::lock_guard _lock{mLock};
+ LOG_ALWAYS_FATAL_IF(mPendingUploads, "terminate called while uploads in progress");
+ if (mUploadThread) {
+ mUploadThread->requestExit();
+ mUploadThread->join();
+ mUploadThread = nullptr;
+ }
+ onDestroy();
}
- if (!sEglManager.hasEglContext()) {
- sUploadThread->queue().runSync([]() {
- sEglManager.initialize();
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ bool uploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) {
+ ATRACE_CALL();
+ beginUpload();
+ bool result = onUploadHardwareBitmap(bitmap, format, graphicBuffer);
+ endUpload();
+ return result;
+ }
+
+ void postIdleTimeoutCheck() {
+ mUploadThread->queue().postDelayed(5000_ms, [this](){ this->idleTimeoutCheck(); });
+ }
+
+protected:
+ std::mutex mLock;
+ sp<ThreadBase> mUploadThread = nullptr;
+
+private:
+ virtual void onInitialize() = 0;
+ virtual void onIdle() = 0;
+ virtual void onDestroy() = 0;
+
+ virtual bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) = 0;
+ virtual void onBeginUpload() = 0;
+
+ bool shouldTimeOutLocked() {
+ nsecs_t durationSince = systemTime() - mLastUpload;
+ return durationSince > 2000_ms;
+ }
+
+ void idleTimeoutCheck() {
+ std::lock_guard _lock{mLock};
+ if (mPendingUploads == 0 && shouldTimeOutLocked()) {
+ onIdle();
+ } else {
+ this->postIdleTimeoutCheck();
+ }
+ }
+
+ void beginUpload() {
+ std::lock_guard _lock{mLock};
+ mPendingUploads++;
+
+ if (!mUploadThread) {
+ mUploadThread = new ThreadBase{};
+ }
+ if (!mUploadThread->isRunning()) {
+ mUploadThread->start("GrallocUploadThread");
+ }
+
+ onBeginUpload();
+ }
+
+ void endUpload() {
+ std::lock_guard _lock{mLock};
+ mPendingUploads--;
+ mLastUpload = systemTime();
+ }
+
+ int mPendingUploads = 0;
+ nsecs_t mLastUpload = 0;
+};
+
+#define FENCE_TIMEOUT 2000000000
+
+class EGLUploader : public AHBUploader {
+private:
+ void onInitialize() override {}
+ void onDestroy() override {
+ mEglManager.destroy();
+ }
+ void onIdle() override {
+ mEglManager.destroy();
+ }
+
+ void onBeginUpload() override {
+ if (!mEglManager.hasEglContext()) {
+ mUploadThread->queue().runSync([this]() {
+ this->mEglManager.initialize();
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ });
+
+ this->postIdleTimeoutCheck();
+ }
+ }
+
+
+ EGLDisplay getUploadEglDisplay() {
+ std::lock_guard _lock{mLock};
+ LOG_ALWAYS_FATAL_IF(!mEglManager.hasEglContext(), "Forgot to begin an upload?");
+ return mEglManager.eglDisplay();
+ }
+
+ bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) override {
+ ATRACE_CALL();
+
+ EGLDisplay display = getUploadEglDisplay();
+
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ // We use an EGLImage to access the content of the GraphicBuffer
+ // The EGL image is later bound to a 2D texture
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ AutoEglImage autoImage(display, clientBuffer);
+ if (autoImage.image == EGL_NO_IMAGE_KHR) {
+ ALOGW("Could not create EGL image, err =%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ return false;
+ }
+
+ {
+ ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
+ EGLSyncKHR fence = mUploadThread->queue().runSync([&]() -> EGLSyncKHR {
+ AutoSkiaGlTexture glTexture;
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
+ GL_CHECKPOINT(MODERATE);
+
+ // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
+ // provide.
+ // But asynchronous in sense that driver may upload texture onto hardware buffer
+ // when we first use it in drawing
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
+ format.format, format.type, bitmap.getPixels());
+ GL_CHECKPOINT(MODERATE);
+
+ EGLSyncKHR uploadFence =
+ eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
+ LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR,
+ "Could not create sync fence %#x", eglGetError());
+ glFlush();
+ return uploadFence;
+ });
+
+ EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
+ LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
+ "Failed to wait for the fence %#x", eglGetError());
+
+ eglDestroySyncKHR(display, fence);
+ }
+ return true;
+ }
+
+ renderthread::EglManager mEglManager;
+};
+
+class VkUploader : public AHBUploader {
+private:
+ void onInitialize() override {
+ std::lock_guard _lock{mLock};
+ if (!mUploadThread) {
+ mUploadThread = new ThreadBase{};
+ }
+ if (!mUploadThread->isRunning()) {
+ mUploadThread->start("GrallocUploadThread");
+ }
+
+ mUploadThread->queue().post([this]() {
+ std::lock_guard _lock{mVkLock};
+ if (!mVulkanManager.hasVkContext()) {
+ mVulkanManager.initialize();
+ }
});
- sUploadThread->queue().postDelayed(5000_ms, checkIdleTimeout);
}
-}
+ void onDestroy() override {
+ mGrContext.reset();
+ mVulkanManager.destroy();
+ }
+ void onIdle() override {
+ mGrContext.reset();
+ }
-static void endUpload() {
- std::lock_guard _lock{sLock};
- sPendingUploads--;
- sLastUpload = systemTime();
-}
+ void onBeginUpload() override {
+ {
+ std::lock_guard _lock{mVkLock};
+ if (!mVulkanManager.hasVkContext()) {
+ LOG_ALWAYS_FATAL_IF(mGrContext,
+ "GrContext exists with no VulkanManager for vulkan uploads");
+ mUploadThread->queue().runSync([this]() {
+ mVulkanManager.initialize();
+ });
+ }
+ }
+ if (!mGrContext) {
+ GrContextOptions options;
+ mGrContext = mVulkanManager.createContext(options);
+ LOG_ALWAYS_FATAL_IF(!mGrContext, "failed to create GrContext for vulkan uploads");
+ this->postIdleTimeoutCheck();
+ }
+ }
-static EGLDisplay getUploadEglDisplay() {
- std::lock_guard _lock{sLock};
- LOG_ALWAYS_FATAL_IF(!sEglManager.hasEglContext(), "Forgot to begin an upload?");
- return sEglManager.eglDisplay();
-}
+ bool onUploadHardwareBitmap(const SkBitmap& bitmap, const FormatInfo& format,
+ sp<GraphicBuffer> graphicBuffer) override {
+ ATRACE_CALL();
+
+ std::lock_guard _lock{mLock};
+
+ sk_sp<SkImage> image = SkImage::MakeFromAHardwareBufferWithData(mGrContext.get(),
+ bitmap.pixmap(), reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()));
+ return (image.get() != nullptr);
+ }
+
+ sk_sp<GrContext> mGrContext;
+ renderthread::VulkanManager mVulkanManager;
+ std::mutex mVkLock;
+};
bool HardwareBitmapUploader::hasFP16Support() {
static std::once_flag sOnce;
@@ -105,16 +297,7 @@
return hasFP16Support;
}
-#define FENCE_TIMEOUT 2000000000
-
-struct FormatInfo {
- PixelFormat pixelFormat;
- GLint format, type;
- bool isSupported = false;
- bool valid = true;
-};
-
-static FormatInfo determineFormat(const SkBitmap& skBitmap) {
+static FormatInfo determineFormat(const SkBitmap& skBitmap, bool usingGL) {
FormatInfo formatInfo;
switch (skBitmap.info().colorType()) {
case kRGBA_8888_SkColorType:
@@ -124,15 +307,18 @@
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.format = GL_RGBA;
formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
break;
case kRGBA_F16_SkColorType:
formatInfo.isSupported = HardwareBitmapUploader::hasFP16Support();
if (formatInfo.isSupported) {
formatInfo.type = GL_HALF_FLOAT;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+ formatInfo.vkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
} else {
formatInfo.type = GL_UNSIGNED_BYTE;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
}
formatInfo.format = GL_RGBA;
break;
@@ -141,12 +327,14 @@
formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
formatInfo.format = GL_RGB;
formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
+ formatInfo.vkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
break;
case kGray_8_SkColorType:
- formatInfo.isSupported = true;
+ formatInfo.isSupported = usingGL;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.format = GL_LUMINANCE;
formatInfo.type = GL_UNSIGNED_BYTE;
+ formatInfo.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
@@ -172,29 +360,37 @@
}
}
-class ScopedUploadRequest {
-public:
- ScopedUploadRequest() { beginUpload(); }
- ~ScopedUploadRequest() { endUpload(); }
-};
+
+static void createUploader(bool usingGL) {
+ static std::mutex lock;
+ std::lock_guard _lock{lock};
+ if (!sUploader.get()) {
+ if (usingGL) {
+ sUploader = new EGLUploader();
+ } else {
+ sUploader = new VkUploader();
+ }
+ }
+}
sk_sp<Bitmap> HardwareBitmapUploader::allocateHardwareBitmap(const SkBitmap& sourceBitmap) {
ATRACE_CALL();
- FormatInfo format = determineFormat(sourceBitmap);
+ bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+ uirenderer::RenderPipelineType::SkiaGL;
+
+ FormatInfo format = determineFormat(sourceBitmap, usingGL);
if (!format.valid) {
return nullptr;
}
- ScopedUploadRequest _uploadRequest{};
-
SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
sp<GraphicBuffer> buffer = new GraphicBuffer(
static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
format.pixelFormat,
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
+ std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) +
"]");
status_t error = buffer->initCheck();
@@ -203,64 +399,24 @@
return nullptr;
}
- EGLDisplay display = getUploadEglDisplay();
+ createUploader(usingGL);
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
- // We use an EGLImage to access the content of the GraphicBuffer
- // The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
- AutoEglImage autoImage(display, clientBuffer);
- if (autoImage.image == EGL_NO_IMAGE_KHR) {
- ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ if (!sUploader->uploadHardwareBitmap(bitmap, format, buffer)) {
return nullptr;
}
-
- {
- ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
- EGLSyncKHR fence = sUploadThread->queue().runSync([&]() -> EGLSyncKHR {
- AutoSkiaGlTexture glTexture;
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
- GL_CHECKPOINT(MODERATE);
-
- // glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
- // provide.
- // But asynchronous in sense that driver may upload texture onto hardware buffer when we
- // first
- // use it in drawing
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
- format.type, bitmap.getPixels());
- GL_CHECKPOINT(MODERATE);
-
- EGLSyncKHR uploadFence =
- eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
- LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
- eglGetError());
- glFlush();
- return uploadFence;
- });
-
- EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
- LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
- "Failed to wait for the fence %#x", eglGetError());
-
- eglDestroySyncKHR(display, fence);
- }
-
- return Bitmap::createFrom(buffer.get(), bitmap.colorType(), bitmap.refColorSpace(),
+ return Bitmap::createFrom(buffer, bitmap.colorType(), bitmap.refColorSpace(),
bitmap.alphaType(), Bitmap::computePalette(bitmap));
}
+void HardwareBitmapUploader::initialize() {
+ bool usingGL = uirenderer::Properties::getRenderPipelineType() ==
+ uirenderer::RenderPipelineType::SkiaGL;
+ createUploader(usingGL);
+ sUploader->initialize();
+}
+
void HardwareBitmapUploader::terminate() {
- std::lock_guard _lock{sLock};
- LOG_ALWAYS_FATAL_IF(sPendingUploads, "terminate called while uploads in progress");
- if (sUploadThread) {
- sUploadThread->requestExit();
- sUploadThread->join();
- sUploadThread = nullptr;
- }
- sEglManager.destroy();
+ sUploader->destroy();
}
} // namespace android::uirenderer
diff --git a/libs/hwui/HardwareBitmapUploader.h b/libs/hwui/HardwareBitmapUploader.h
index 6f41e6d..c300593 100644
--- a/libs/hwui/HardwareBitmapUploader.h
+++ b/libs/hwui/HardwareBitmapUploader.h
@@ -22,9 +22,11 @@
class ANDROID_API HardwareBitmapUploader {
public:
- static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+ static void initialize();
static void terminate();
+ static sk_sp<Bitmap> allocateHardwareBitmap(const SkBitmap& sourceBitmap);
+
static bool hasFP16Support();
};
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index fe633e9..fb60a96 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -28,6 +28,7 @@
#include "hwui/Bitmap.h"
#include "utils/Color.h"
#include "utils/MathUtils.h"
+#include "utils/TraceUtils.h"
using namespace android::uirenderer::renderthread;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index a00a36f..721a115 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -25,6 +25,7 @@
#include <SkPictureRecorder.h>
#include "TreeInfo.h"
#include "VectorDrawable.h"
+#include "thread/CommonPool.h"
#include "utils/TraceUtils.h"
#include <unistd.h>
@@ -49,10 +50,6 @@
unpinImages();
}
-TaskManager* SkiaPipeline::getTaskManager() {
- return mRenderThread.cacheManager().getTaskManager();
-}
-
void SkiaPipeline::onDestroyHardwareResources() {
unpinImages();
mRenderThread.cacheManager().trimStaleResources();
@@ -225,42 +222,21 @@
}
}
-class SkiaPipeline::SavePictureProcessor : public TaskProcessor<bool> {
-public:
- explicit SavePictureProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
-
- struct SavePictureTask : public Task<bool> {
- sk_sp<SkData> data;
- std::string filename;
- };
-
- void savePicture(const sk_sp<SkData>& data, const std::string& filename) {
- sp<SavePictureTask> task(new SavePictureTask());
- task->data = data;
- task->filename = filename;
- TaskProcessor<bool>::add(task);
- }
-
- virtual void onProcess(const sp<Task<bool>>& task) override {
- ATRACE_NAME("SavePictureTask");
- SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
-
- if (0 == access(t->filename.c_str(), F_OK)) {
- task->setResult(false);
+static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filename) {
+ CommonPool::post([data, filename] {
+ if (0 == access(filename.c_str(), F_OK)) {
return;
}
- SkFILEWStream stream(t->filename.c_str());
+ SkFILEWStream stream(filename.c_str());
if (stream.isValid()) {
- stream.write(t->data->data(), t->data->size());
+ stream.write(data->data(), data->size());
stream.flush();
SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
- t->filename.c_str());
+ filename.c_str());
}
-
- task->setResult(true);
- }
-};
+ });
+}
SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
@@ -297,16 +273,10 @@
ATRACE_END();
// offload saving to file in a different thread
- if (!mSavePictureProcessor.get()) {
- TaskManager* taskManager = getTaskManager();
- mSavePictureProcessor = new SavePictureProcessor(
- taskManager->canRunTasks() ? taskManager : nullptr);
- }
if (1 == mCaptureSequence) {
- mSavePictureProcessor->savePicture(data, mCapturedFile);
+ savePictureAsync(data, mCapturedFile);
} else {
- mSavePictureProcessor->savePicture(
- data,
+ savePictureAsync(data,
mCapturedFile + "_" + std::to_string(mCaptureSequence));
}
mCaptureSequence--;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 7381e04..41d8646 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -33,8 +33,6 @@
explicit SkiaPipeline(renderthread::RenderThread& thread);
virtual ~SkiaPipeline();
- TaskManager* getTaskManager() override;
-
void onDestroyHardwareResources() override;
bool pinImages(std::vector<SkImage*>& mutableImages) override;
@@ -157,11 +155,7 @@
* mCaptureSequence counts how many frames are left to take in the sequence.
*/
int mCaptureSequence = 0;
- /**
- * mSavePictureProcessor is used to run the file saving code in a separate thread.
- */
- class SavePictureProcessor;
- sp<SavePictureProcessor> mSavePictureProcessor;
+
/**
* mRecorder holds the current picture recorder. We could store it on the stack to support
* parallel tryCapture calls (not really needed).
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 6c04232..8b02c11 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -23,6 +23,7 @@
#include "pipeline/skia/SkiaMemoryTracer.h"
#include "Properties.h"
#include "renderstate/RenderState.h"
+#include "thread/CommonPool.h"
#include <GrContextOptions.h>
#include <SkExecutor.h>
@@ -76,29 +77,15 @@
mGrContext->setResourceCacheLimits(mMaxResources, mMaxResourceBytes);
}
-class CacheManager::SkiaTaskProcessor : public TaskProcessor<bool>, public SkExecutor {
+class CommonPoolExecutor : public SkExecutor {
public:
- explicit SkiaTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
-
- // This is really a Task<void> but that doesn't really work when Future<>
- // expects to be able to get/set a value
- struct SkiaTask : public Task<bool> {
- std::function<void()> func;
- };
-
virtual void add(std::function<void(void)> func) override {
- sp<SkiaTask> task(new SkiaTask());
- task->func = func;
- TaskProcessor<bool>::add(task);
- }
-
- virtual void onProcess(const sp<Task<bool> >& task) override {
- SkiaTask* t = static_cast<SkiaTask*>(task.get());
- t->func();
- task->setResult(true);
+ CommonPool::post(std::move(func));
}
};
+static CommonPoolExecutor sDefaultExecutor;
+
void CacheManager::configureContext(GrContextOptions* contextOptions, const void* identity, ssize_t size) {
contextOptions->fAllowPathMaskCaching = true;
@@ -107,12 +94,7 @@
// provided to Skia.
contextOptions->fGlyphCacheTextureMaximumBytes = GrNextSizePow2(mMaxSurfaceArea);
- if (mTaskManager.canRunTasks()) {
- if (!mTaskProcessor.get()) {
- mTaskProcessor = new SkiaTaskProcessor(&mTaskManager);
- }
- contextOptions->fExecutor = mTaskProcessor.get();
- }
+ contextOptions->fExecutor = &sDefaultExecutor;
auto& cache = skiapipeline::ShaderCache::get();
cache.initShaderDiskCache(identity, size);
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 66f04f1..b0286e8 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -24,8 +24,6 @@
#include <vector>
#include "pipeline/skia/VectorDrawableAtlas.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
namespace android {
@@ -54,8 +52,6 @@
size_t getCacheSize() const { return mMaxResourceBytes; }
size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
- TaskManager* getTaskManager() { return &mTaskManager; }
-
private:
friend class RenderThread;
@@ -78,10 +74,6 @@
};
sp<skiapipeline::VectorDrawableAtlas> mVectorDrawableAtlas;
-
- class SkiaTaskProcessor;
- sp<SkiaTaskProcessor> mTaskProcessor;
- TaskManager mTaskManager;
};
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 091775dbe7..baa41c1 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -27,8 +27,10 @@
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "thread/CommonPool.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
+#include "utils/TraceUtils.h"
#include "../Properties.h"
#include <cutils/properties.h>
@@ -103,7 +105,7 @@
, mOpaque(!translucent)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
, mJankTracker(&thread.globalProfileData(), thread.mainDisplayInfo())
- , mProfiler(mJankTracker.frames())
+ , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
, mContentDrawBounds(0, 0, 0, 0)
, mRenderPipeline(std::move(renderPipeline)) {
rootRenderNode->makeRoot();
@@ -603,31 +605,14 @@
if (mFrameFences.size()) {
ATRACE_CALL();
for (auto& fence : mFrameFences) {
- fence->getResult();
+ fence.get();
}
mFrameFences.clear();
}
}
-class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
-public:
- explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
-
- virtual void onProcess(const sp<Task<bool> >& task) override {
- FuncTask* t = static_cast<FuncTask*>(task.get());
- t->func();
- task->setResult(true);
- }
-};
-
void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
- if (!mFrameWorkProcessor.get()) {
- mFrameWorkProcessor = new FuncTaskProcessor(mRenderPipeline->getTaskManager());
- }
- sp<FuncTask> task(new FuncTask());
- task->func = func;
- mFrameFences.push_back(task);
- mFrameWorkProcessor->add(task);
+ mFrameFences.push_back(CommonPool::async(std::move(func)));
}
int64_t CanvasContext::getFrameNumber() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4da0eac..abca342 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -28,8 +28,6 @@
#include "ReliableSurface.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
-#include "thread/Task.h"
-#include "thread/TaskProcessor.h"
#include <EGL/egl.h>
#include <SkBitmap.h>
@@ -42,6 +40,7 @@
#include <set>
#include <string>
#include <vector>
+#include <future>
namespace android {
namespace uirenderer {
@@ -274,15 +273,7 @@
// Stores the bounds of the main content.
Rect mContentDrawBounds;
- // TODO: This is really a Task<void> but that doesn't really work
- // when Future<> expects to be able to get/set a value
- struct FuncTask : public Task<bool> {
- std::function<void()> func;
- };
- class FuncTaskProcessor;
-
- std::vector<sp<FuncTask>> mFrameFences;
- sp<TaskProcessor<bool>> mFrameWorkProcessor;
+ std::vector<std::future<void>> mFrameFences;
std::unique_ptr<IRenderPipeline> mRenderPipeline;
std::vector<std::function<void(int64_t)>> mFrameCompleteCallbacks;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 2cfc8df..0502eb8 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -75,7 +75,6 @@
virtual void renderLayers(const LightGeometry& lightGeometry,
LayerUpdateQueue* layerUpdateQueue, bool opaque,
const LightInfo& lightInfo) = 0;
- virtual TaskManager* getTaskManager() = 0;
virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) = 0;
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 34f76d9..1bcb819 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -31,6 +31,7 @@
#include "renderthread/RenderThread.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
+#include "utils/TraceUtils.h"
#include <ui/GraphicBuffer.h>
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 08edd20..6cce319 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -28,6 +28,8 @@
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
+#include "utils/TraceUtils.h"
+#include "../HardwareBitmapUploader.h"
#ifdef HWUI_GLES_WRAP_ENABLED
#include "debug/GlesDriver.h"
@@ -52,9 +54,6 @@
// using just a few large reads.
static const size_t EVENT_BUFFER_SIZE = 100;
-// Slight delay to give the UI time to push us a new frame before we replay
-static const nsecs_t DISPATCH_FRAME_CALLBACKS_DELAY = milliseconds_to_nanoseconds(4);
-
static bool gHasRenderThreadInstance = false;
static JVMAttachHook gOnStartHook = nullptr;
@@ -171,6 +170,7 @@
mDisplayInfo = DeviceInfo::get()->displayInfo();
nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
mTimeLord.setFrameInterval(frameIntervalNanos);
+ mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
initializeDisplayEventReceiver();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
@@ -311,7 +311,7 @@
if (mTimeLord.vsyncReceived(vsyncEvent) && !mFrameCallbackTaskPending) {
ATRACE_NAME("queue mFrameCallbackTask");
mFrameCallbackTaskPending = true;
- nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
+ nsecs_t runAt = (vsyncEvent + mDispatchFrameDelay);
queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
}
}
@@ -416,6 +416,7 @@
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
requireVkContext();
}
+ HardwareBitmapUploader::initialize();
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 329b4b9..5f43b48 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -24,6 +24,7 @@
#include "TimeLord.h"
#include "thread/ThreadBase.h"
#include "WebViewFunctorManager.h"
+#include "utils/TimeUtils.h"
#include <GrContext.h>
#include <SkBitmap.h>
@@ -40,6 +41,7 @@
namespace android {
class Bitmap;
+class AutoBackendTextureRelease;
namespace uirenderer {
@@ -134,6 +136,7 @@
friend class DispatchFrameCallbacks;
friend class RenderProxy;
friend class DummyVsyncSource;
+ friend class android::AutoBackendTextureRelease;
friend class android::uirenderer::TestUtils;
friend class android::uirenderer::WebViewFunctor;
friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
@@ -164,6 +167,7 @@
bool mFrameCallbackTaskPending;
TimeLord mTimeLord;
+ nsecs_t mDispatchFrameDelay = 4_ms;
RenderState* mRenderState;
EglManager* mEglManager;
WebViewFunctorManager& mFunctorManager;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 6dacc7a..9916da5 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -23,6 +23,7 @@
#include "RenderThread.h"
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
+#include "utils/TraceUtils.h"
#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
index 077a8f7..65d95ad 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ b/libs/hwui/surfacetexture/ImageConsumer.cpp
@@ -24,13 +24,17 @@
#include "renderthread/VulkanManager.h"
#include "utils/Color.h"
#include <GrAHardwareBufferUtils.h>
+#include <GrBackendSurface.h>
// Macro for including the SurfaceTexture name in log messages
#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
+using namespace android::uirenderer::renderthread;
+
namespace android {
void ImageConsumer::onFreeBufferLocked(int slotIndex) {
+ // This callback may be invoked on any thread.
mImageSlots[slotIndex].clear();
}
@@ -46,55 +50,141 @@
mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
}
+/**
+ * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
+ * that keeps GPU resources alive until the last SKImage object using them is destroyed.
+ */
+class AutoBackendTextureRelease {
+public:
+ static void releaseProc(SkImage::ReleaseContext releaseContext);
+
+ AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer);
+
+ const GrBackendTexture& getTexture() const { return mBackendTexture; }
+
+ void ref() { mUsageCount++; }
+
+ void unref(bool releaseImage);
+
+ inline sk_sp<SkImage> getImage() { return mImage; }
+
+ void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace,
+ GrContext* context);
+
+private:
+ // The only way to invoke dtor is with unref, when mUsageCount is 0.
+ ~AutoBackendTextureRelease() {}
+
+ GrBackendTexture mBackendTexture;
+ GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+ GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+
+ // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
+ // are held by SkImages.
+ int mUsageCount = 1;
+
+ // mImage is the SkImage created from mBackendTexture.
+ sk_sp<SkImage> mImage;
+};
+
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) {
+ bool createProtectedImage =
+ 0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
+ GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
+ context,
+ reinterpret_cast<AHardwareBuffer*>(buffer),
+ buffer->getPixelFormat(),
+ false);
+ mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
+ context,
+ reinterpret_cast<AHardwareBuffer*>(buffer),
+ buffer->getWidth(),
+ buffer->getHeight(),
+ &mDeleteProc,
+ &mDeleteCtx,
+ createProtectedImage,
+ backendFormat,
+ false);
+}
+
+void AutoBackendTextureRelease::unref(bool releaseImage) {
+ if (!RenderThread::isCurrent()) {
+ // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
+ // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
+ // thread safe.
+ RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
+ return;
+ }
+
+ if (releaseImage) {
+ mImage.reset();
+ }
+
+ mUsageCount--;
+ if (mUsageCount <= 0) {
+ if (mBackendTexture.isValid()) {
+ mDeleteProc(mDeleteCtx);
+ mBackendTexture = {};
+ }
+ delete this;
+ }
+}
+
+void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) {
+ AutoBackendTextureRelease* textureRelease =
+ reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
+ textureRelease->unref(false);
+}
+
+void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer,
+ android_dataspace dataspace, GrContext* context) {
+ SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
+ graphicBuffer->getPixelFormat());
+ mImage = SkImage::MakeFromTexture(context,
+ mBackendTexture,
+ kTopLeft_GrSurfaceOrigin,
+ colorType,
+ kPremul_SkAlphaType,
+ uirenderer::DataSpaceToColorSpace(dataspace),
+ releaseProc,
+ this);
+ if (mImage.get()) {
+ // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+ ref();
+ }
+}
+
void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
android_dataspace dataspace, bool forceCreate,
GrContext* context) {
- if (!mImage.get() || dataspace != mDataspace || forceCreate) {
+ if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace
+ || forceCreate) {
if (!graphicBuffer.get()) {
clear();
return;
}
- if (!mBackendTexture.isValid()) {
- clear();
- bool createProtectedImage =
- 0 != (graphicBuffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
- GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
- context,
- reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
- graphicBuffer->getPixelFormat(),
- false);
- mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
- context,
- reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()),
- graphicBuffer->getWidth(),
- graphicBuffer->getHeight(),
- &mDeleteProc,
- &mDeleteCtx,
- createProtectedImage,
- backendFormat,
- false);
+ if (!mTextureRelease) {
+ mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get());
}
+
mDataspace = dataspace;
- SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
- graphicBuffer->getPixelFormat());
- mImage = SkImage::MakeFromTexture(context,
- mBackendTexture,
- kTopLeft_GrSurfaceOrigin,
- colorType,
- kPremul_SkAlphaType,
- uirenderer::DataSpaceToColorSpace(dataspace));
+ mTextureRelease->makeImage(graphicBuffer, dataspace, context);
}
}
void ImageConsumer::ImageSlot::clear() {
- mImage.reset();
- if (mBackendTexture.isValid()) {
- mDeleteProc(mDeleteCtx);
- mBackendTexture = {};
+ if (mTextureRelease) {
+ // The following unref counteracts the initial mUsageCount of 1, set by default initializer.
+ mTextureRelease->unref(true);
+ mTextureRelease = nullptr;
}
}
+sk_sp<SkImage> ImageConsumer::ImageSlot::getImage() {
+ return mTextureRelease ? mTextureRelease->getImage() : nullptr;
+}
+
sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
uirenderer::RenderState& renderState) {
BufferItem item;
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
index eee0a0a..2fdece9 100644
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ b/libs/hwui/surfacetexture/ImageConsumer.h
@@ -25,7 +25,6 @@
#include <cutils/compiler.h>
#include <gui/BufferItem.h>
#include <system/graphics.h>
-#include <GrBackendSurface.h>
namespace GrAHardwareBufferUtils {
typedef void* DeleteImageCtx;
@@ -38,6 +37,7 @@
class RenderState;
}
+class AutoBackendTextureRelease;
class SurfaceTexture;
/*
@@ -81,16 +81,14 @@
void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
bool forceCreate, GrContext* context);
+
void clear();
inline EGLSyncKHR& eglFence() { return mEglFence; }
- inline sk_sp<SkImage> getImage() { return mImage; }
+ sk_sp<SkImage> getImage();
private:
- // mImage is the SkImage created from mGraphicBuffer.
- sk_sp<SkImage> mImage;
-
// the dataspace associated with the current image
android_dataspace mDataspace;
@@ -100,11 +98,11 @@
*/
EGLSyncKHR mEglFence;
- GrBackendTexture mBackendTexture;
-
- GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
-
- GrAHardwareBufferUtils::DeleteImageCtx mDeleteCtx;
+ /**
+ * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage.
+ * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear".
+ */
+ AutoBackendTextureRelease* mTextureRelease = nullptr;
};
/**
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 0e61899e..b45dbc8 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -21,6 +21,7 @@
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/scenes/TestSceneBase.h"
+#include "utils/TraceUtils.h"
#include <benchmark/benchmark.h>
#include <gui/Surface.h>
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
deleted file mode 100644
index 4153bae..0000000
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2016 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 <benchmark/benchmark.h>
-
-#include "thread/Task.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
-#include "thread/ThreadBase.h"
-
-#include <atomic>
-#include <vector>
-
-using namespace android;
-using namespace android::uirenderer;
-
-class TrivialTask : public Task<char> {};
-
-class TrivialProcessor : public TaskProcessor<char> {
-public:
- explicit TrivialProcessor(TaskManager* manager) : TaskProcessor(manager) {}
- virtual ~TrivialProcessor() {}
- virtual void onProcess(const sp<Task<char>>& task) override {
- TrivialTask* t = static_cast<TrivialTask*>(task.get());
- t->setResult(reinterpret_cast<intptr_t>(t) % 16 == 0 ? 'a' : 'b');
- }
-};
-
-class TestThread : public ThreadBase, public virtual RefBase {};
-
-void BM_TaskManager_allocateTask(benchmark::State& state) {
- std::vector<sp<TrivialTask>> tasks;
- tasks.reserve(state.max_iterations);
-
- while (state.KeepRunning()) {
- tasks.emplace_back(new TrivialTask);
- benchmark::DoNotOptimize(tasks.back());
- }
-}
-BENCHMARK(BM_TaskManager_allocateTask);
-
-void BM_TaskManager_enqueueTask(benchmark::State& state) {
- TaskManager taskManager;
- sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
- std::vector<sp<TrivialTask>> tasks;
- tasks.reserve(state.max_iterations);
-
- while (state.KeepRunning()) {
- tasks.emplace_back(new TrivialTask);
- benchmark::DoNotOptimize(tasks.back());
- processor->add(tasks.back());
- }
-
- for (sp<TrivialTask>& task : tasks) {
- task->getResult();
- }
-}
-BENCHMARK(BM_TaskManager_enqueueTask);
-
-void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
- TaskManager taskManager;
- sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
- std::vector<sp<TrivialTask>> tasks;
- tasks.reserve(state.max_iterations);
-
- while (state.KeepRunning()) {
- tasks.emplace_back(new TrivialTask);
- benchmark::DoNotOptimize(tasks.back());
- processor->add(tasks.back());
- }
- state.ResumeTiming();
- for (sp<TrivialTask>& task : tasks) {
- benchmark::DoNotOptimize(task->getResult());
- }
- tasks.clear();
- state.PauseTiming();
-}
-BENCHMARK(BM_TaskManager_enqueueRunDeleteTask);
-
-void BM_Thread_enqueueTask(benchmark::State& state) {
- sp<TestThread> thread{new TestThread};
- thread->start();
-
- atomic_int counter(0);
- int expected = 0;
- while (state.KeepRunning()) {
- expected++;
- thread->queue().post([&counter]() { counter++; });
- }
- thread->queue().runSync([]() {});
-
- thread->requestExit();
- thread->join();
- if (counter != expected) {
- printf("Ran %d lambads, should have been %d\n", counter.load(), expected);
- }
-}
-BENCHMARK(BM_Thread_enqueueTask);
-
-void BM_Thread_enqueueRunDeleteTask(benchmark::State& state) {
- sp<TestThread> thread{new TestThread};
- thread->start();
- std::vector<std::future<int>> tasks;
- tasks.reserve(state.max_iterations);
-
- int expected = 0;
- while (state.KeepRunning()) {
- tasks.emplace_back(thread->queue().async([expected]() -> int { return expected + 1; }));
- expected++;
- }
- state.ResumeTiming();
- expected = 0;
- for (auto& future : tasks) {
- if (future.get() != ++expected) {
- printf("Mismatch expected %d vs. observed %d\n", expected, future.get());
- }
- }
- tasks.clear();
- state.PauseTiming();
-}
-BENCHMARK(BM_Thread_enqueueRunDeleteTask);
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp
new file mode 100644
index 0000000..c564ed6
--- /dev/null
+++ b/libs/hwui/tests/unit/CommonPoolTests.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "thread/CommonPool.h"
+
+#include <array>
+#include <condition_variable>
+#include <set>
+#include <thread>
+#include "unistd.h"
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(CommonPool, post) {
+ std::atomic_bool ran(false);
+ CommonPool::post([&ran] { ran = true; });
+ for (int i = 0; !ran && i < 1000; i++) {
+ usleep(1);
+ }
+ EXPECT_TRUE(ran) << "Failed to flip atomic after 1 second";
+}
+
+TEST(CommonPool, threadCount) {
+ std::set<pid_t> threads;
+ std::array<std::future<pid_t>, 64> futures;
+ for (int i = 0; i < futures.size(); i++) {
+ futures[i] = CommonPool::async([] {
+ usleep(10);
+ return gettid();
+ });
+ }
+ for (auto& f : futures) {
+ threads.insert(f.get());
+ }
+ EXPECT_EQ(threads.size(), CommonPool::THREAD_COUNT);
+ EXPECT_EQ(0, threads.count(gettid()));
+}
+
+TEST(CommonPool, singleThread) {
+ std::mutex mutex;
+ std::condition_variable fence;
+ bool isProcessing = false;
+ bool queuedSecond = false;
+
+ auto f1 = CommonPool::async([&] {
+ {
+ std::unique_lock lock{mutex};
+ isProcessing = true;
+ fence.notify_all();
+ while (!queuedSecond) {
+ fence.wait(lock);
+ }
+ }
+ return gettid();
+ });
+
+ {
+ std::unique_lock lock{mutex};
+ while (!isProcessing) {
+ fence.wait(lock);
+ }
+ }
+
+ auto f2 = CommonPool::async([] {
+ return gettid();
+ });
+
+ {
+ std::unique_lock lock{mutex};
+ queuedSecond = true;
+ fence.notify_all();
+ }
+
+ auto tid1 = f1.get();
+ auto tid2 = f2.get();
+ EXPECT_EQ(tid1, tid2);
+ EXPECT_NE(gettid(), tid1);
+}
+
+TEST(CommonPool, fullQueue) {
+ std::mutex lock;
+ std::condition_variable fence;
+ bool signaled = false;
+ static constexpr auto QUEUE_COUNT = CommonPool::THREAD_COUNT + CommonPool::QUEUE_SIZE + 10;
+ std::atomic_int queuedCount{0};
+ std::array<std::future<void>, QUEUE_COUNT> futures;
+
+ std::thread queueThread{[&] {
+ for (int i = 0; i < QUEUE_COUNT; i++) {
+ futures[i] = CommonPool::async([&] {
+ std::unique_lock _lock{lock};
+ while (!signaled) {
+ fence.wait(_lock);
+ }
+ });
+ queuedCount++;
+ }
+ }};
+
+ int previous;
+ do {
+ previous = queuedCount.load();
+ usleep(10000);
+ } while (previous != queuedCount.load());
+
+ EXPECT_GT(queuedCount.load(), CommonPool::QUEUE_SIZE);
+ EXPECT_LT(queuedCount.load(), QUEUE_COUNT);
+
+ {
+ std::unique_lock _lock{lock};
+ signaled = true;
+ fence.notify_all();
+ }
+
+ queueThread.join();
+ EXPECT_EQ(queuedCount.load(), QUEUE_COUNT);
+
+ // Ensure all our tasks are finished before return as they have references to the stack
+ for (auto& f : futures) {
+ f.get();
+ }
+}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index 63d1540..83d888c 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -22,9 +22,6 @@
#include "debug/NullGlesDriver.h"
#include "hwui/Typeface.h"
#include "tests/common/LeakChecker.h"
-#include "thread/Task.h"
-#include "thread/TaskManager.h"
-#include "thread/TaskProcessor.h"
#include <signal.h>
diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h
deleted file mode 100644
index bb750ca..0000000
--- a/libs/hwui/thread/Barrier.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_BARRIER_H
-#define ANDROID_HWUI_BARRIER_H
-
-#include <utils/Condition.h>
-
-namespace android {
-namespace uirenderer {
-
-class Barrier {
-public:
- explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
- : mType(type), mOpened(false) {}
- ~Barrier() {}
-
- void open() {
- Mutex::Autolock l(mLock);
- mOpened = true;
- mCondition.signal(mType);
- }
-
- void wait() const {
- Mutex::Autolock l(mLock);
- while (!mOpened) {
- mCondition.wait(mLock);
- }
- }
-
-private:
- Condition::WakeUpType mType;
- volatile bool mOpened;
- mutable Mutex mLock;
- mutable Condition mCondition;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_BARRIER_H
diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp
new file mode 100644
index 0000000..7f94a15
--- /dev/null
+++ b/libs/hwui/thread/CommonPool.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#include "CommonPool.h"
+
+#include <sys/resource.h>
+#include <utils/Trace.h>
+#include "renderthread/RenderThread.h"
+
+#include <array>
+
+namespace android {
+namespace uirenderer {
+
+CommonPool::CommonPool() {
+ ATRACE_CALL();
+
+ CommonPool* pool = this;
+ // Create 2 workers
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ std::thread worker([pool, i] {
+ {
+ std::array<char, 20> name{"hwuiTask"};
+ snprintf(name.data(), name.size(), "hwuiTask%d", i);
+ auto self = pthread_self();
+ pthread_setname_np(self, name.data());
+ setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
+ auto startHook = renderthread::RenderThread::getOnStartHook();
+ if (startHook) {
+ startHook(name.data());
+ }
+ }
+ pool->workerLoop();
+ });
+ worker.detach();
+ }
+}
+
+void CommonPool::post(Task&& task) {
+ static CommonPool pool;
+ pool.enqueue(std::move(task));
+}
+
+void CommonPool::enqueue(Task&& task) {
+ std::unique_lock lock(mLock);
+ while (!mWorkQueue.hasSpace()) {
+ lock.unlock();
+ usleep(100);
+ lock.lock();
+ }
+ mWorkQueue.push(std::move(task));
+ if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
+ mCondition.notify_one();
+ }
+}
+
+void CommonPool::workerLoop() {
+ std::unique_lock lock(mLock);
+ while (true) {
+ if (!mWorkQueue.hasWork()) {
+ mWaitingThreads++;
+ mCondition.wait(lock);
+ mWaitingThreads--;
+ }
+ // Need to double-check that work is still available now that we have the lock
+ // It may have already been grabbed by a different thread
+ while (mWorkQueue.hasWork()) {
+ auto work = mWorkQueue.pop();
+ lock.unlock();
+ work();
+ lock.lock();
+ }
+ }
+}
+
+} // namespace uirenderer
+} // namespace android
\ No newline at end of file
diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h
new file mode 100644
index 0000000..aef2990
--- /dev/null
+++ b/libs/hwui/thread/CommonPool.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_BASE_COMMONPOOL_H
+#define FRAMEWORKS_BASE_COMMONPOOL_H
+
+#include "utils/Macros.h"
+
+#include <log/log.h>
+
+#include <condition_variable>
+#include <functional>
+#include <future>
+#include <mutex>
+
+namespace android {
+namespace uirenderer {
+
+template <class T, int SIZE>
+class ArrayQueue {
+ PREVENT_COPY_AND_ASSIGN(ArrayQueue);
+ static_assert(SIZE > 0, "Size must be positive");
+
+public:
+ ArrayQueue() = default;
+ ~ArrayQueue() = default;
+
+ constexpr size_t capacity() const { return SIZE; }
+ constexpr bool hasWork() const { return mHead != mTail; }
+ constexpr bool hasSpace() const { return ((mHead + 1) % SIZE) != mTail; }
+ constexpr int size() const {
+ if (mHead > mTail) {
+ return mHead - mTail;
+ } else {
+ return mTail - mHead + SIZE;
+ }
+ }
+
+ constexpr void push(T&& t) {
+ int newHead = (mHead + 1) % SIZE;
+ LOG_ALWAYS_FATAL_IF(newHead == mTail, "no space");
+
+ mBuffer[mHead] = std::move(t);
+ mHead = newHead;
+ }
+
+ constexpr T&& pop() {
+ LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
+ int index = mTail;
+ mTail = (mTail + 1) % SIZE;
+ return std::move(mBuffer[index]);
+ }
+
+private:
+ T mBuffer[SIZE];
+ int mHead = 0;
+ int mTail = 0;
+};
+
+class CommonPool {
+ PREVENT_COPY_AND_ASSIGN(CommonPool);
+
+public:
+ using Task = std::function<void()>;
+ static constexpr auto THREAD_COUNT = 2;
+ static constexpr auto QUEUE_SIZE = 128;
+
+ static void post(Task&& func);
+
+ template <class F>
+ static auto async(F&& func) -> std::future<decltype(func())> {
+ typedef std::packaged_task<decltype(func())()> task_t;
+ auto task = std::make_shared<task_t>(std::forward<F>(func));
+ post([task]() { std::invoke(*task); });
+ return task->get_future();
+ }
+
+ template <class F>
+ static auto runSync(F&& func) -> decltype(func()) {
+ std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
+ post([&task]() { std::invoke(task); });
+ return task.get_future().get();
+ };
+
+private:
+ CommonPool();
+ ~CommonPool() {}
+
+ void enqueue(Task&&);
+
+ void workerLoop();
+
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ int mWaitingThreads = 0;
+ ArrayQueue<Task, QUEUE_SIZE> mWorkQueue;
+};
+
+} // namespace uirenderer
+} // namespace android
+
+#endif // FRAMEWORKS_BASE_COMMONPOOL_H
diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h
deleted file mode 100644
index df53348e..0000000
--- a/libs/hwui/thread/Future.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_FUTURE_H
-#define ANDROID_HWUI_FUTURE_H
-
-#include <utils/RefBase.h>
-
-#include "Barrier.h"
-
-namespace android {
-namespace uirenderer {
-
-template <typename T>
-class Future : public LightRefBase<Future<T> > {
-public:
- explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE)
- : mBarrier(type), mResult() {}
- ~Future() {}
-
- /**
- * Returns the result of this future, blocking if
- * the result is not available yet.
- */
- T get() const {
- mBarrier.wait();
- return mResult;
- }
-
- /**
- * This method must be called only once.
- */
- void produce(T result) {
- mResult = result;
- mBarrier.open();
- }
-
-private:
- Barrier mBarrier;
- T mResult;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_FUTURE_H
diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h
deleted file mode 100644
index 6d33ac4..0000000
--- a/libs/hwui/thread/Signal.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_SIGNAL_H
-#define ANDROID_HWUI_SIGNAL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/threads.h>
-
-namespace android {
-namespace uirenderer {
-
-class Signal {
-public:
- explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
- : mType(type), mSignaled(false) {}
- ~Signal() {}
-
- void signal() {
- {
- Mutex::Autolock l(mLock);
- mSignaled = true;
- }
- mCondition.signal(mType);
- }
-
- void wait() {
- Mutex::Autolock l(mLock);
- while (!mSignaled) {
- mCondition.wait(mLock);
- }
- mSignaled = false;
- }
-
-private:
- Condition::WakeUpType mType;
- volatile bool mSignaled;
- mutable Mutex mLock;
- mutable Condition mCondition;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_SIGNAL_H
diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h
deleted file mode 100644
index 228ce19..0000000
--- a/libs/hwui/thread/Task.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_TASK_H
-#define ANDROID_HWUI_TASK_H
-
-#include <utils/RefBase.h>
-#include <utils/Trace.h>
-
-#include "Future.h"
-
-namespace android {
-namespace uirenderer {
-
-class TaskBase : public RefBase {
-public:
- TaskBase() {}
- virtual ~TaskBase() {}
-};
-
-template <typename T>
-class Task : public TaskBase {
-public:
- Task() : mFuture(new Future<T>()) {}
- virtual ~Task() {}
-
- T getResult() const { return mFuture->get(); }
-
- void setResult(T result) { mFuture->produce(result); }
-
-protected:
- const sp<Future<T> >& future() const { return mFuture; }
-
-private:
- sp<Future<T> > mFuture;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_TASK_H
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
deleted file mode 100644
index de10ff1..0000000
--- a/libs/hwui/thread/TaskManager.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <sys/resource.h>
-#include <sys/sysinfo.h>
-
-#include "Task.h"
-#include "TaskManager.h"
-#include "TaskProcessor.h"
-#include "utils/MathUtils.h"
-#include "renderthread/RenderThread.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Manager
-///////////////////////////////////////////////////////////////////////////////
-
-TaskManager::TaskManager() {
- // Get the number of available CPUs. This value does not change over time.
- int cpuCount = sysconf(_SC_NPROCESSORS_CONF);
-
- // Really no point in making more than 2 of these worker threads, but
- // we do want to limit ourselves to 1 worker thread on dual-core devices.
- int workerCount = cpuCount > 2 ? 2 : 1;
- for (int i = 0; i < workerCount; i++) {
- String8 name;
- name.appendFormat("hwuiTask%d", i + 1);
- mThreads.push_back(new WorkerThread(name));
- }
-}
-
-TaskManager::~TaskManager() {
- for (size_t i = 0; i < mThreads.size(); i++) {
- mThreads[i]->exit();
- }
-}
-
-bool TaskManager::canRunTasks() const {
- return mThreads.size() > 0;
-}
-
-void TaskManager::stop() {
- for (size_t i = 0; i < mThreads.size(); i++) {
- mThreads[i]->exit();
- }
-}
-
-bool TaskManager::addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor) {
- if (mThreads.size() > 0) {
- TaskWrapper wrapper(task, processor);
-
- size_t minQueueSize = INT_MAX;
- sp<WorkerThread> thread;
-
- for (size_t i = 0; i < mThreads.size(); i++) {
- if (mThreads[i]->getTaskCount() < minQueueSize) {
- thread = mThreads[i];
- minQueueSize = mThreads[i]->getTaskCount();
- }
- }
-
- return thread->addTask(wrapper);
- }
- return false;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Thread
-///////////////////////////////////////////////////////////////////////////////
-
-status_t TaskManager::WorkerThread::readyToRun() {
- setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
- auto onStartHook = renderthread::RenderThread::getOnStartHook();
- if (onStartHook) {
- onStartHook(mName.c_str());
- }
-
- return NO_ERROR;
-}
-
-bool TaskManager::WorkerThread::threadLoop() {
- mSignal.wait();
- std::vector<TaskWrapper> tasks;
- {
- Mutex::Autolock l(mLock);
- tasks.swap(mTasks);
- }
-
- for (size_t i = 0; i < tasks.size(); i++) {
- const TaskWrapper& task = tasks[i];
- task.mProcessor->process(task.mTask);
- }
-
- return true;
-}
-
-bool TaskManager::WorkerThread::addTask(const TaskWrapper& task) {
- if (!isRunning()) {
- run(mName.string(), PRIORITY_DEFAULT);
- } else if (exitPending()) {
- return false;
- }
-
- {
- Mutex::Autolock l(mLock);
- mTasks.push_back(task);
- }
- mSignal.signal();
-
- return true;
-}
-
-size_t TaskManager::WorkerThread::getTaskCount() const {
- Mutex::Autolock l(mLock);
- return mTasks.size();
-}
-
-void TaskManager::WorkerThread::exit() {
- requestExit();
- mSignal.signal();
-}
-
-} // namespace uirenderer
-} // namespace android
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
deleted file mode 100644
index 6c67222..0000000
--- a/libs/hwui/thread/TaskManager.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_TASK_MANAGER_H
-#define ANDROID_HWUI_TASK_MANAGER_H
-
-#include <utils/Mutex.h>
-#include <utils/String8.h>
-#include <utils/Thread.h>
-
-#include "Signal.h"
-
-#include <vector>
-
-namespace android {
-namespace uirenderer {
-
-template <typename T>
-class Task;
-class TaskBase;
-
-template <typename T>
-class TaskProcessor;
-class TaskProcessorBase;
-
-class TaskManager {
-public:
- TaskManager();
- ~TaskManager();
-
- /**
- * Returns true if this task manager can run tasks,
- * false otherwise. This method will typically return
- * false on a single CPU core device.
- */
- bool canRunTasks() const;
-
- /**
- * Stops all allocated threads. Adding tasks will start
- * the threads again as necessary.
- */
- void stop();
-
-private:
- template <typename T>
- friend class TaskProcessor;
-
- template <typename T>
- bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
- return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
- }
-
- bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
-
- struct TaskWrapper {
- TaskWrapper() : mTask(), mProcessor() {}
-
- TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor)
- : mTask(task), mProcessor(processor) {}
-
- sp<TaskBase> mTask;
- sp<TaskProcessorBase> mProcessor;
- };
-
- class WorkerThread : public Thread {
- public:
- explicit WorkerThread(const String8& name)
- : Thread(false), mSignal(Condition::WAKE_UP_ONE), mName(name) {}
-
- bool addTask(const TaskWrapper& task);
- size_t getTaskCount() const;
- void exit();
-
- private:
- virtual status_t readyToRun() override;
- virtual bool threadLoop() override;
-
- // Lock for the list of tasks
- mutable Mutex mLock;
- std::vector<TaskWrapper> mTasks;
-
- // Signal used to wake up the thread when a new
- // task is available in the list
- mutable Signal mSignal;
-
- const String8 mName;
- };
-
- std::vector<sp<WorkerThread> > mThreads;
-};
-
-} // namespace uirenderer
-} // namespace android
-
-#endif // ANDROID_HWUI_TASK_MANAGER_H
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
deleted file mode 100644
index 8117ae6..0000000
--- a/libs/hwui/thread/TaskProcessor.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HWUI_TASK_PROCESSOR_H
-#define ANDROID_HWUI_TASK_PROCESSOR_H
-
-#include <utils/RefBase.h>
-
-#include "Task.h"
-#include "TaskManager.h"
-
-namespace android {
-namespace uirenderer {
-
-class TaskProcessorBase : public RefBase {
-public:
- TaskProcessorBase() {}
- virtual ~TaskProcessorBase(){};
-
- virtual void process(const sp<TaskBase>& task) = 0;
-};
-
-template <typename T>
-class TaskProcessor : public TaskProcessorBase {
-public:
- explicit TaskProcessor(TaskManager* manager) : mManager(manager) {}
- virtual ~TaskProcessor() {}
-
- void add(const sp<Task<T> >& task) {
- if (!addImpl(task)) {
- // fall back to immediate execution
- process(task);
- }
- }
-
- virtual void onProcess(const sp<Task<T> >& task) = 0;
-
-private:
- bool addImpl(const sp<Task<T> >& task);
-
- virtual void process(const sp<TaskBase>& task) override {
- sp<Task<T> > realTask = static_cast<Task<T>*>(task.get());
- // This is the right way to do it but sp<> doesn't play nice
- // sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
- onProcess(realTask);
- }
-
- TaskManager* mManager;
-};
-
-template <typename T>
-bool TaskProcessor<T>::addImpl(const sp<Task<T> >& task) {
- if (mManager) {
- sp<TaskProcessor<T> > self(this);
- return mManager->addTask(task, self);
- }
- return false;
-}
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_TASK_PROCESSOR_H
diff --git a/libs/hwui/thread/WorkQueue.h b/libs/hwui/thread/WorkQueue.h
index 7a6e638..42f8503 100644
--- a/libs/hwui/thread/WorkQueue.h
+++ b/libs/hwui/thread/WorkQueue.h
@@ -26,7 +26,6 @@
#include <functional>
#include <future>
#include <mutex>
-#include <variant>
#include <vector>
namespace android::uirenderer {
diff --git a/location/java/android/location/GnssCapabilities.java b/location/java/android/location/GnssCapabilities.java
new file mode 100644
index 0000000..6a35920
--- /dev/null
+++ b/location/java/android/location/GnssCapabilities.java
@@ -0,0 +1,153 @@
+/*
+ * 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 android.location;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A container of supported GNSS chipset capabilities.
+ *
+ * @hide
+ */
+@SystemApi
+public final class GnssCapabilities {
+ /** The GNSS chipset supports low power mode. */
+ public static final int LOW_POWER_MODE = 0;
+
+ /** The GNSS chipset supports blacklisting satellites. */
+ public static final int SATELLITE_BLACKLIST = 1;
+
+ /** The GNSS chipset supports geofencing. */
+ public static final int GEOFENCING = 2;
+
+ /** The GNSS chipset supports measurements.*/
+ public static final int MEASUREMENTS = 3;
+
+ /** The GNSS chipset supports navigation messages. */
+ public static final int NAV_MESSAGES = 4;
+
+ /** The GNSS chipset supports measurement corrections. */
+ public static final int MEASUREMENT_CORRECTIONS = 5;
+
+ /** The GNSS chipset supports line-of-sight satellite identification measurement corrections. */
+ public static final int MEASUREMENT_CORRECTIONS_LOS_SATS = 6;
+
+ /** The GNSS chipset supports per satellite excess-path-length measurement corrections. */
+ public static final int MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH = 7;
+
+ /** The GNSS chipset supports reflecting planes measurement corrections. */
+ public static final int MEASUREMENT_CORRECTIONS_REFLECTING_PLANE = 8;
+
+ private static final int MIN_CAPABILITY = 0;
+ private static final int MAX_CAPABILITY = MEASUREMENT_CORRECTIONS_REFLECTING_PLANE;
+
+ /**
+ * GNSS capability.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ LOW_POWER_MODE,
+ SATELLITE_BLACKLIST,
+ GEOFENCING,
+ MEASUREMENTS,
+ NAV_MESSAGES,
+ MEASUREMENT_CORRECTIONS,
+ MEASUREMENT_CORRECTIONS_LOS_SATS,
+ MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH,
+ MEASUREMENT_CORRECTIONS_REFLECTING_PLANE
+ })
+ public @interface Capability {}
+
+ /**
+ * @hide
+ */
+ public static final long INVALID_CAPABILITIES = -1;
+
+ /** A bitmask of supported GNSS capabilities. */
+ private final long mGnssCapabilities;
+
+ static GnssCapabilities of(long gnssCapabilities) {
+ return new GnssCapabilities(gnssCapabilities);
+ }
+
+ private GnssCapabilities(long gnssCapabilities) {
+ mGnssCapabilities = gnssCapabilities;
+ }
+
+ /**
+ * Returns {@code true} if the {@code capability} is supported by the GNSS implementation.
+ */
+ public boolean hasCapability(@Capability int capability) {
+ return isValidCapability(capability) && (mGnssCapabilities & (1 << capability)) != 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("GnssCapabilities: (");
+ int capability = 0;
+ boolean addSeparator = false;
+ long gnssCapabilities = mGnssCapabilities;
+ while (gnssCapabilities != 0) {
+ if ((gnssCapabilities & 1) != 0) {
+ if (addSeparator) {
+ sb.append(' ');
+ } else {
+ addSeparator = true;
+ }
+ sb.append(toStringCapability(capability));
+ }
+ gnssCapabilities >>= 1;
+ ++capability;
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ private boolean isValidCapability(@Capability int capability) {
+ return capability >= MIN_CAPABILITY && capability <= MAX_CAPABILITY;
+ }
+
+ private static String toStringCapability(@Capability int capability) {
+ switch (capability) {
+ case LOW_POWER_MODE:
+ return "LOW_POWER_MODE";
+ case SATELLITE_BLACKLIST:
+ return "SATELLITE_BLACKLIST";
+ case GEOFENCING:
+ return "GEOFENCING";
+ case MEASUREMENTS:
+ return "MEASUREMENTS";
+ case NAV_MESSAGES:
+ return "NAV_MESSAGES";
+ case MEASUREMENT_CORRECTIONS:
+ return "MEASUREMENT_CORRECTIONS";
+ case MEASUREMENT_CORRECTIONS_LOS_SATS:
+ return "MEASUREMENT_CORRECTIONS_LOS_SATS";
+ case MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH:
+ return "MEASUREMENT_CORRECTIONS_EXCESS_PATH_LENGTH";
+ case MEASUREMENT_CORRECTIONS_REFLECTING_PLANE:
+ return "MEASUREMENT_CORRECTIONS_REFLECTING_PLANE";
+ default:
+ return "Unknown(" + capability + ")";
+ }
+ }
+}
diff --git a/location/java/android/location/GnssMeasurementCallbackTransport.java b/location/java/android/location/GnssMeasurementCallbackTransport.java
index 1188b13b..8cb8c0b 100644
--- a/location/java/android/location/GnssMeasurementCallbackTransport.java
+++ b/location/java/android/location/GnssMeasurementCallbackTransport.java
@@ -63,7 +63,7 @@
measurementCorrections, getContext().getPackageName());
}
- protected int getGnssCapabilities() throws RemoteException {
+ protected long getGnssCapabilities() throws RemoteException {
return mLocationManager.getGnssCapabilities(getContext().getPackageName());
}
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 60c7748..ce464b7 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -42,6 +42,8 @@
public static final int CONSTELLATION_BEIDOU = 5;
/** Constellation type constant for Galileo. */
public static final int CONSTELLATION_GALILEO = 6;
+ /** Constellation type constant for IRNSS. */
+ public static final int CONSTELLATION_IRNSS = 7;
/** @hide */
public static final int GNSS_SV_FLAGS_NONE = 0;
@@ -94,7 +96,7 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS,
- CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO})
+ CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO, CONSTELLATION_IRNSS})
public @interface ConstellationType {}
final int[] mSvidWithFlags;
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index c371c5f..a4582b7 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -66,7 +66,7 @@
boolean addGnssMeasurementsListener(in IGnssMeasurementsListener listener, in String packageName);
void injectGnssMeasurementCorrections(in GnssMeasurementCorrections corrections,
in String packageName);
- int getGnssCapabilities(in String packageName);
+ long getGnssCapabilities(in String packageName);
void removeGnssMeasurementsListener(in IGnssMeasurementsListener listener);
boolean addGnssNavigationMessageListener(
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index dd179f3..edf304c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -167,11 +167,21 @@
/**
* Broadcast intent action when the set of enabled location providers changes. To check the
- * status of a provider, use {@link #isProviderEnabled(String)}.
+ * status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
+ * include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
+ * whose state has changed.
+ *
+ * @see #EXTRA_PROVIDER_NAME
*/
public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
/**
+ * Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the name
+ * of the location provider that has changed, to be used with location provider APIs.
+ */
+ public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
+
+ /**
* Broadcast intent action when the device location mode changes. To check the location mode,
* use {@link #isLocationEnabled()}.
*/
@@ -1976,15 +1986,19 @@
}
/**
- * Returns the integer capability flags of the GNSS chipset as defined in {@code
- * IGnssCallback.hal}
+ * Returns the supported capabilities of the GNSS chipset or {@code null} if there is an error
+ * in obtaining the capabilities.
*
* @hide
*/
@SystemApi
- public int getGnssCapabilities() {
+ public @Nullable GnssCapabilities getGnssCapabilities() {
try {
- return mGnssMeasurementCallbackTransport.getGnssCapabilities();
+ long gnssCapabilities = mGnssMeasurementCallbackTransport.getGnssCapabilities();
+ if (gnssCapabilities == GnssCapabilities.INVALID_CAPABILITIES) {
+ return null;
+ }
+ return GnssCapabilities.of(gnssCapabilities);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
index c201770..d6f8a7c 100644
--- a/location/java/android/location/SettingInjectorService.java
+++ b/location/java/android/location/SettingInjectorService.java
@@ -16,6 +16,7 @@
package android.location;
+import android.annotation.NonNull;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -58,17 +59,17 @@
* </pre>
* Here:
* <ul>
- * <li>title: The {@link android.preference.Preference#getTitle()} value. The title should make
- * it clear which apps are affected by the setting, typically by including the name of the
- * developer. For example, "Acme Corp. ads preferences." </li>
+ * <li>title: The {@link android.preference.Preference#getTitle()} value. The title should make
+ * it clear which apps are affected by the setting, typically by including the name of the
+ * developer. For example, "Acme Corp. ads preferences." </li>
*
- * <li>icon: The {@link android.preference.Preference#getIcon()} value. Typically this will be a
- * generic icon for the developer rather than the icon for an individual app.</li>
+ * <li>icon: The {@link android.preference.Preference#getIcon()} value. Typically this will be a
+ * generic icon for the developer rather than the icon for an individual app.</li>
*
- * <li>settingsActivity: the activity which is launched to allow the user to modify the setting
- * value. The activity must be in the same package as the subclass of
- * {@link SettingInjectorService}. The activity should use your own branding to help emphasize
- * to the user that it is not part of the system settings.</li>
+ * <li>settingsActivity: the activity which is launched to allow the user to modify the setting
+ * value. The activity must be in the same package as the subclass of
+ * {@link SettingInjectorService}. The activity should use your own branding to help emphasize
+ * to the user that it is not part of the system settings.</li>
* </ul>
*
* To ensure a good user experience, your {@link android.app.Application#onCreate()},
@@ -206,6 +207,8 @@
* Returns the {@link android.preference.Preference#getSummary()} value (allowed to be null or
* empty). Should not perform unpredictably-long operations such as network access--see the
* running-time comments in the class-level javadoc.
+ * <p/>
+ * This method is called on KitKat, and Q+ devices.
*
* @return the {@link android.preference.Preference#getSummary()} value
*/
@@ -234,7 +237,7 @@
/**
* Sends a broadcast to refresh the injected settings on location settings page.
*/
- public static final void refreshSettings(Context context) {
+ public static final void refreshSettings(@NonNull Context context) {
Intent intent = new Intent(ACTION_INJECTED_SETTING_CHANGED);
context.sendBroadcast(intent);
}
diff --git a/media/OWNERS b/media/OWNERS
index eb26367..72c8952 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -3,7 +3,9 @@
elaurent@google.com
etalvala@google.com
gkasten@google.com
+hdmoon@google.com
hunga@google.com
+insun@google.com
jaewan@google.com
jmtrivi@google.com
jsharkey@android.com
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 5cd3621..13ff108 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -274,8 +274,7 @@
* successful transition. Any other value will be an error. Call {@link #getState()} to
* determine the current state. </p>
*/
-public class MediaPlayer2 implements AutoCloseable
- , AudioRouting {
+public class MediaPlayer2 implements AutoCloseable, AudioRouting {
static {
System.loadLibrary("media2_jni");
native_init();
@@ -1810,12 +1809,10 @@
public MediaTimestamp getTimestamp() {
try {
// TODO: get the timestamp from native side
- return new MediaTimestamp.Builder()
- .setMediaTimestamp(
- getCurrentPosition() * 1000L,
- System.nanoTime(),
- getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f)
- .build();
+ return new MediaTimestamp(
+ getCurrentPosition() * 1000L,
+ System.nanoTime(),
+ getState() == PLAYER_STATE_PLAYING ? getPlaybackParams().getSpeed() : 0.f);
} catch (IllegalStateException e) {
return null;
}
@@ -2643,13 +2640,11 @@
return;
}
Iterator<Value> in = playerMsg.getValuesList().iterator();
- SubtitleData data = new SubtitleData.Builder()
- .setSubtitleData(
- in.next().getInt32Value(), // trackIndex
- in.next().getInt64Value(), // startTimeUs
- in.next().getInt64Value(), // durationUs
- in.next().getBytesValue().toByteArray()) // data
- .build();
+ SubtitleData data = new SubtitleData(
+ in.next().getInt32Value(), // trackIndex
+ in.next().getInt64Value(), // startTimeUs
+ in.next().getInt64Value(), // durationUs
+ in.next().getBytesValue().toByteArray()); // data
sendEvent(new EventNotifier() {
@Override
public void notify(EventCallback callback) {
@@ -2673,11 +2668,9 @@
return;
}
Iterator<Value> in = playerMsg.getValuesList().iterator();
- data = new TimedMetaData.Builder()
- .setTimedMetaData(
- in.next().getInt64Value(), // timestampUs
- in.next().getBytesValue().toByteArray()) // metaData
- .build();
+ data = new TimedMetaData(
+ in.next().getInt64Value(), // timestampUs
+ in.next().getBytesValue().toByteArray()); // metaData
} else {
data = null;
}
@@ -3463,7 +3456,7 @@
* @param uuid of selected crypto scheme
* @return this
*/
- public Builder setUuid(@NonNull UUID uuid) {
+ public @NonNull Builder setUuid(@NonNull UUID uuid) {
this.mUUID = uuid;
return this;
}
@@ -3480,7 +3473,7 @@
* @param keySetId identifier of a persisted offline key
* @return this
*/
- public Builder setKeySetId(@Nullable byte[] keySetId) {
+ public @NonNull Builder setKeySetId(@Nullable byte[] keySetId) {
this.mKeySetId = keySetId;
return this;
}
@@ -3494,7 +3487,7 @@
* @param initData container-specific DRM initialization data
* @return this
*/
- public Builder setInitData(@Nullable byte[] initData) {
+ public @NonNull Builder setInitData(@Nullable byte[] initData) {
this.mInitData = initData;
return this;
}
@@ -3505,7 +3498,7 @@
* @param mimeType mime type to the content
* @return this
*/
- public Builder setMimeType(@Nullable String mimeType) {
+ public @NonNull Builder setMimeType(@Nullable String mimeType) {
this.mMimeType = mimeType;
return this;
}
@@ -3519,7 +3512,7 @@
* @param keyType type of the key request
* @return this
*/
- public Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
+ public @NonNull Builder setKeyType(@MediaPlayer2.MediaDrmKeyType int keyType) {
this.mKeyType = keyType;
return this;
}
@@ -3531,7 +3524,8 @@
* @param optionalParameters optional parameters to be included in a key request
* @return this
*/
- public Builder setOptionalParameters(@Nullable Map<String, String> optionalParameters) {
+ public @NonNull Builder setOptionalParameters(
+ @Nullable Map<String, String> optionalParameters) {
this.mOptionalParameters = optionalParameters;
return this;
}
@@ -3540,7 +3534,7 @@
* @return an immutable {@link MediaPlayer2.DrmPreparationInfo} representing the
* settings of this builder
*/
- public MediaPlayer2.DrmPreparationInfo build() {
+ public @NonNull MediaPlayer2.DrmPreparationInfo build() {
return new MediaPlayer2.DrmPreparationInfo(mUUID, mKeySetId, mInitData, mMimeType,
mKeyType, mOptionalParameters);
}
@@ -3597,7 +3591,8 @@
* @return a {@link DrmPreparationInfo} object to initialize DRM playback, or null to skip
* DRM initialization
*/
- public DrmPreparationInfo onDrmInfo(MediaPlayer2 mp, DataSourceDesc dsd, DrmInfo drmInfo) {
+ public @Nullable DrmPreparationInfo onDrmInfo(@NonNull MediaPlayer2 mp,
+ @NonNull DataSourceDesc dsd, @NonNull DrmInfo drmInfo) {
return null;
}
@@ -3630,11 +3625,13 @@
* @param request a {@link MediaDrm.KeyRequest} prepared using the
* {@link DrmPreparationInfo} returned from
* {@link #onDrmInfo(MediaPlayer2, DataSourceDesc, DrmInfo)}
- * @return the response to {@code request} (from license server)
+ * @return the response to {@code request} (from license server); returning {@code null} or
+ * throwing an {@link RuntimeException} from this callback would trigger an
+ * {@link EventCallback#onError}.
*/
- public byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp, @NonNull DataSourceDesc dsd,
- @NonNull MediaDrm.KeyRequest request) {
- return null;
+ public @NonNull byte[] onDrmKeyRequest(@NonNull MediaPlayer2 mp,
+ @NonNull DataSourceDesc dsd, @NonNull MediaDrm.KeyRequest request) {
+ return new byte[0];
}
/**
@@ -4144,7 +4141,7 @@
/**
* Returns the PSSH info of the data source for each supported DRM scheme.
*/
- public Map<UUID, byte[]> getPssh() {
+ public @NonNull Map<UUID, byte[]> getPssh() {
return mMapPssh;
}
@@ -4153,7 +4150,7 @@
* It effectively identifies the subset of the source's DRM schemes which
* are supported by the device too.
*/
- public List<UUID> getSupportedSchemes() {
+ public @NonNull List<UUID> getSupportedSchemes() {
return Arrays.asList(mSupportedSchemes);
}
@@ -4276,7 +4273,7 @@
* Extends MediaDrm.MediaDrmException
*/
public static final class NoDrmSchemeException extends MediaDrmException {
- public NoDrmSchemeException(String detailMessage) {
+ public NoDrmSchemeException(@Nullable String detailMessage) {
super(detailMessage);
}
}
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
index 20d6391..6822ea5 100644
--- a/media/apex/java/android/media/Session2Command.java
+++ b/media/apex/java/android/media/Session2Command.java
@@ -32,6 +32,10 @@
* If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
* {@link #getCustomCommand()} shouldn't be {@code null}.
* <p>
+ * Refer to the
+ * <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a>
+ * class for the list of valid commands.
+ * <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>
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 6a595d2..f9080a7 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1820,6 +1820,21 @@
"android.media.action.MICROPHONE_MUTE_CHANGED";
/**
+ * Broadcast Action: speakerphone state changed.
+ *
+ * You <em>cannot</em> receive this through components declared
+ * in manifests, only by explicitly registering for it with
+ * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
+ * Context.registerReceiver()}.
+ *
+ * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
+ * speakerphone functionality is enabled or not.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
+ "android.media.action.SPEAKERPHONE_STATE_CHANGED";
+
+ /**
* Sets the audio mode.
* <p>
* The audio mode encompasses audio routing AND the behavior of
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
index 333cd2d..4aa0b90 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.NonNull;
+import android.media.AudioAttributes.AttributeUsage;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioMixingRule;
import android.media.projection.MediaProjection;
@@ -41,12 +42,9 @@
* <pre>
* MediaProjection mediaProjection;
* // Retrieve a audio capable projection from the MediaProjectionManager
- * AudioAttributes mediaAttr = new AudioAttributes.Builder()
- * .setUsage(AudioAttributes.USAGE_MEDIA)
- * .build();
* AudioPlaybackCaptureConfiguration config =
* new AudioPlaybackCaptureConfiguration.Builder(mediaProjection)
- * .addMatchingUsage(mediaAttr)
+ * .addMatchingUsage(AudioAttributes.USAGE_MEDIA)
* .build();
* AudioRecord record = new AudioRecord.Builder()
* .setAudioPlaybackCaptureConfig(config)
@@ -68,6 +66,15 @@
}
/**
+ * @return the {@code MediaProjection} used to build this object.
+ * @see {@code Builder.Builder}
+ */
+ public @NonNull MediaProjection getMediaProjection() {
+ return mProjection;
+ }
+
+
+ /**
* Returns a mix that routes audio back into the app while still playing it from the speakers.
*
* @param audioFormat The format in which to capture the audio.
@@ -78,9 +85,6 @@
.setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER)
.build();
}
- MediaProjection getMediaProjection() {
- return mProjection;
- }
/** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */
public static final class Builder {
@@ -121,14 +125,13 @@
* attributes.
*
* @throws IllegalStateException if called in conjunction with
- * {@link #excludeUsage(AudioAttributes)}.
+ * {@link #excludeUsage(int)}.
*/
- public @NonNull Builder addMatchingUsage(@NonNull AudioAttributes audioAttributes) {
- Preconditions.checkNotNull(audioAttributes);
+ public @NonNull Builder addMatchingUsage(@AttributeUsage int usage) {
Preconditions.checkState(
mUsageMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
- mAudioMixingRuleBuilder
- .addRule(audioAttributes, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+ mAudioMixingRuleBuilder.addRule(new AudioAttributes.Builder().setUsage(usage).build(),
+ AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
mUsageMatchType = MATCH_TYPE_INCLUSIVE;
return this;
}
@@ -156,14 +159,15 @@
* given attributes.
*
* @throws IllegalStateException if called in conjunction with
- * {@link #addMatchingUsage(AudioAttributes)}.
+ * {@link #addMatchingUsage(int)}.
*/
- public @NonNull Builder excludeUsage(@NonNull AudioAttributes audioAttributes) {
- Preconditions.checkNotNull(audioAttributes);
+ public @NonNull Builder excludeUsage(@AttributeUsage int usage) {
Preconditions.checkState(
mUsageMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
- mAudioMixingRuleBuilder.excludeRule(audioAttributes,
- AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+ mAudioMixingRuleBuilder.excludeRule(new AudioAttributes.Builder()
+ .setUsage(usage)
+ .build(),
+ AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
mUsageMatchType = MATCH_TYPE_EXCLUSIVE;
return this;
}
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 09cfa95..41e059b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1014,9 +1014,9 @@
* frame indicates the number of samples per channel, e.g. 100 frames for a stereo compressed
* stream corresponds to 200 decoded interleaved PCM samples.
* @param delayInFrames number of frames to be ignored at the beginning of the stream. A value
- * of 0 indicates no padding is to be applied.
- * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
* of 0 indicates no delay is to be applied.
+ * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
+ * of 0 indicates no padding is to be applied.
*/
public void setOffloadDelayPadding(@IntRange(from = 0) int delayInFrames,
@IntRange(from = 0) int paddingInFrames) {
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4cd8971..23db27d 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1359,7 +1359,7 @@
if (file == null) {
throw new NullPointerException("file cannot be null");
}
- initForFilename(file.getName());
+ initForFilename(file.getAbsolutePath());
}
/**
diff --git a/media/java/android/media/ExternalRingtonesCursorWrapper.java b/media/java/android/media/ExternalRingtonesCursorWrapper.java
index dd4c77a..ea63a3a 100644
--- a/media/java/android/media/ExternalRingtonesCursorWrapper.java
+++ b/media/java/android/media/ExternalRingtonesCursorWrapper.java
@@ -16,7 +16,6 @@
package android.media;
-import android.content.ContentProvider;
import android.database.Cursor;
import android.database.CursorWrapper;
import android.net.Uri;
@@ -28,19 +27,18 @@
* @hide
*/
public class ExternalRingtonesCursorWrapper extends CursorWrapper {
+ private Uri mUri;
- private int mUserId;
-
- public ExternalRingtonesCursorWrapper(Cursor cursor, int userId) {
+ public ExternalRingtonesCursorWrapper(Cursor cursor, Uri uri) {
super(cursor);
- mUserId = userId;
+ mUri = uri;
}
public String getString(int index) {
- String result = super.getString(index);
if (index == RingtoneManager.URI_COLUMN_INDEX) {
- result = ContentProvider.maybeAddUserId(Uri.parse(result), mUserId).toString();
+ return mUri.toString();
+ } else {
+ return super.getString(index);
}
- return result;
}
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 4bc3897..a687c14 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.util.Log;
@@ -31,6 +32,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -1332,7 +1334,7 @@
private Range<Rational> mBlockAspectRatioRange;
private Range<Long> mBlocksPerSecondRange;
private Map<Size, Range<Long>> mMeasuredFrameRates;
- private Vector<PerformancePoint> mPerformancePoints;
+ private List<PerformancePoint> mPerformancePoints;
private Range<Integer> mFrameRateRange;
private int mBlockWidth;
@@ -1620,45 +1622,136 @@
* rate.
*/
public static final class PerformancePoint {
+ private Size mBlockSize; // codec block size in macroblocks
+ private int mWidth; // width in macroblocks
+ private int mHeight; // height in macroblocks
+ private int mMaxFrameRate; // max frames per second
+ private long mMaxMacroBlockRate; // max macro block rate
+
/**
- * (Maximum) number of macroblocks in the frame.
+ * Maximum number of macroblocks in the frame.
*
* Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
* Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
* is characterized using such blocks.
+ *
+ * @hide
*/
- public final int macroBlocks;
+ @TestApi
+ public int getMaxMacroBlocks() {
+ return saturateLongToInt(mWidth * (long)mHeight);
+ }
/**
- * (Maximum) frame rate in frames per second.
+ * Maximum frame rate in frames per second.
+ *
+ * @hide
*/
- public final int frameRate;
+ @TestApi
+ public int getMaxFrameRate() {
+ return mMaxFrameRate;
+ }
/**
- * (Maximum) number of macroblocks processed per second.
+ * Maximum number of macroblocks processed per second.
+ *
+ * @hide
*/
- public final long macroBlockRate;
+ @TestApi
+ public long getMaxMacroBlockRate() {
+ return mMaxMacroBlockRate;
+ }
- /* package private */
- PerformancePoint(int width_, int height_, int frameRate_, int maxFrameRate_) {
- macroBlocks = saturateLongToInt(
- ((Math.max(1, (long)width_) + 15) / 16)
- * ((Math.max(1, (long)height_) + 15) / 16));
- frameRate = Math.max(1, frameRate_);
- macroBlockRate = Math.max(maxFrameRate_, frameRate) * macroBlocks;
+ /** Convert to a debug string */
+ public String toString() {
+ int blockWidth = 16 * mBlockSize.getWidth();
+ int blockHeight = 16 * mBlockSize.getHeight();
+ int origRate = (int)Utils.divUp(mMaxMacroBlockRate, getMaxMacroBlocks());
+ String info = (mWidth * 16) + "x" + (mHeight * 16) + "@" + origRate;
+ if (origRate < mMaxFrameRate) {
+ info += ", max " + mMaxFrameRate + "fps";
+ }
+ if (blockWidth > 16 || blockHeight > 16) {
+ info += ", " + blockWidth + "x" + blockHeight + " blocks";
+ }
+ return "PerformancePoint(" + info + ")";
+ }
+
+ /**
+ * Create a detailed performance point with custom max frame rate and macroblock size.
+ *
+ * @param width frame width in pixels
+ * @param height frame height in pixels
+ * @param frameRate frames per second for frame width and height
+ * @param maxFrameRate maximum frames per second for any frame size
+ * @param blockSize block size for codec implementation. Must be powers of two in both
+ * width and height.
+ *
+ * @throws IllegalArgumentException if the blockSize dimensions are not powers of two.
+ *
+ * @hide
+ */
+ @TestApi
+ public PerformancePoint(
+ int width, int height, int frameRate, int maxFrameRate,
+ @NonNull Size blockSize) {
+ checkPowerOfTwo(blockSize.getWidth(), "block width");
+ checkPowerOfTwo(blockSize.getHeight(), "block height");
+
+ mBlockSize = new Size(Utils.divUp(blockSize.getWidth(), 16),
+ Utils.divUp(blockSize.getHeight(), 16));
+ // these are guaranteed not to overflow as we decimate by 16
+ mWidth = (int)(Utils.divUp(Math.max(1L, width),
+ Math.max(blockSize.getWidth(), 16))
+ * mBlockSize.getWidth());
+ mHeight = (int)(Utils.divUp(Math.max(1L, height),
+ Math.max(blockSize.getHeight(), 16))
+ * mBlockSize.getHeight());
+ mMaxFrameRate = Math.max(1, Math.max(frameRate, maxFrameRate));
+ mMaxMacroBlockRate = Math.max(1, frameRate) * getMaxMacroBlocks();
+ Log.i("PP", "Created " + this);
+ }
+
+ /**
+ * Convert a performance point to a larger blocksize.
+ *
+ * @param pp performance point
+ * @param blockSize block size for codec implementation
+ *
+ * @hide
+ */
+ @TestApi
+ public PerformancePoint(@NonNull PerformancePoint pp, @NonNull Size newBlockSize) {
+ this(
+ pp.mWidth * 16, pp.mHeight * 16,
+ // guaranteed not to overflow as these were multiplied at construction
+ (int)Utils.divUp(pp.mMaxMacroBlockRate, pp.getMaxMacroBlocks()),
+ pp.mMaxFrameRate,
+ new Size(Math.max(newBlockSize.getWidth(), pp.mBlockSize.getWidth() * 16),
+ Math.max(newBlockSize.getHeight(), pp.mBlockSize.getHeight() * 16))
+ );
+ /*
+ // these are guaranteed not to overflow as size * blockSize is decimated by 16
+ width = align(pp.width * pp.blockSize.getWidth(), blockSize.getWidth());
+ height = align(pp.height * pp.blockSize.getHeight(), blockSize.getHeight());
+ frameRate = pp.frameRate;
+ macroBlockRate = align(pp.macroBlockRate, blockSize.getWidth * blockSize.getHeight());
+ */
+ Log.i("PP", " from " + pp + " and " + newBlockSize);
}
/**
* Create a performance point for a given frame size and frame rate.
*
- * @param width_ width of the frame in pixels
- * @param height_ height of the frame in pixels
- * @param frameRate_ frame rate in frames per second
+ * @param width width of the frame in pixels
+ * @param height height of the frame in pixels
+ * @param frameRate frame rate in frames per second
*/
- public PerformancePoint(int width_, int height_, int frameRate_) {
- this(width_, height_, frameRate_, frameRate_ /* maxFrameRate */);
+ public PerformancePoint(int width, int height, int frameRate) {
+ this(width, height, frameRate, frameRate /* maxFrameRate */, new Size(16, 16));
}
+ /** Saturates a long value to int */
private int saturateLongToInt(long value) {
if (value < Integer.MIN_VALUE) {
return Integer.MIN_VALUE;
@@ -1669,6 +1762,19 @@
}
}
+ /* This method may overflow */
+ private int align(int value, int alignment) {
+ return Utils.divUp(value, alignment) * alignment;
+ }
+
+ /** Checks that value is a power of two. */
+ private void checkPowerOfTwo2(int value, @NonNull String description) {
+ if (value == 0 || (value & (value - 1)) != 0) {
+ throw new IllegalArgumentException(
+ description + " (" + value + ") must be a power of 2");
+ }
+ }
+
/**
* Checks whether the performance point covers a media format.
*
@@ -1680,7 +1786,7 @@
PerformancePoint other = new PerformancePoint(
format.getInteger(MediaFormat.KEY_WIDTH, 0),
format.getInteger(MediaFormat.KEY_HEIGHT, 0),
- // safely convert ceil(double) to int through float case and Math.round
+ // safely convert ceil(double) to int through float cast and Math.round
Math.round((float)(
Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0)
.doubleValue()))));
@@ -1690,7 +1796,7 @@
/**
* Checks whether the performance point covers another performance point. Use this
* method to determine if a performance point advertised by a codec covers the
- * performance point required. This method can also be used for lose ordering as this
+ * performance point required. This method can also be used for loose ordering as this
* method is transitive.
*
* @param other other performance point considered
@@ -1698,91 +1804,139 @@
* @return {@code true} if the performance point covers the other.
*/
public boolean covers(@NonNull PerformancePoint other) {
- return (macroBlocks >= other.macroBlocks
- && frameRate >= other.frameRate
- && macroBlockRate >= other.macroBlockRate);
+ // convert performance points to common block size
+ Size commonSize = getCommonBlockSize(other);
+ PerformancePoint aligned = new PerformancePoint(this, commonSize);
+ PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
+
+ return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks()
+ && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate
+ && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
}
+ private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
+ return new Size(
+ Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
+ Math.max(mBlockSize.getHeight(), other.mBlockSize.getHeight()) * 16);
+ }
@Override
public boolean equals(Object o) {
if (o instanceof PerformancePoint) {
+ // convert performance points to common block size
PerformancePoint other = (PerformancePoint)o;
- return (macroBlocks == other.macroBlocks
- && frameRate == other.frameRate
- && macroBlockRate == other.macroBlockRate);
+ Size commonSize = getCommonBlockSize(other);
+ PerformancePoint aligned = new PerformancePoint(this, commonSize);
+ PerformancePoint otherAligned = new PerformancePoint(other, commonSize);
+
+ return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks()
+ && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate
+ && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate);
}
return false;
}
/** 480p 24fps */
+ @NonNull
public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
/** 576p 25fps */
+ @NonNull
public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
/** 480p 30fps */
+ @NonNull
public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
/** 480p 48fps */
+ @NonNull
public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
/** 576p 50fps */
+ @NonNull
public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
/** 480p 60fps */
+ @NonNull
public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
/** 720p 24fps */
+ @NonNull
public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
/** 720p 25fps */
+ @NonNull
public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
/** 720p 30fps */
+ @NonNull
public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
/** 720p 50fps */
+ @NonNull
public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
/** 720p 60fps */
+ @NonNull
public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
/** 720p 100fps */
+ @NonNull
public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
/** 720p 120fps */
+ @NonNull
public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
/** 720p 200fps */
+ @NonNull
public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
/** 720p 240fps */
+ @NonNull
public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
/** 1080p 24fps */
+ @NonNull
public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
/** 1080p 25fps */
+ @NonNull
public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
/** 1080p 30fps */
+ @NonNull
public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
/** 1080p 50fps */
+ @NonNull
public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
/** 1080p 60fps */
+ @NonNull
public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
/** 1080p 100fps */
+ @NonNull
public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
/** 1080p 120fps */
+ @NonNull
public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
/** 1080p 200fps */
+ @NonNull
public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
/** 1080p 240fps */
+ @NonNull
public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
/** 2160p 24fps */
+ @NonNull
public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
/** 2160p 25fps */
+ @NonNull
public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
/** 2160p 30fps */
+ @NonNull
public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
/** 2160p 50fps */
+ @NonNull
public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
/** 2160p 60fps */
+ @NonNull
public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
/** 2160p 100fps */
+ @NonNull
public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
/** 2160p 120fps */
+ @NonNull
public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
/** 2160p 200fps */
+ @NonNull
public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
/** 2160p 240fps */
+ @NonNull
public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
}
@@ -1803,10 +1957,7 @@
*/
@Nullable
public List<PerformancePoint> getSupportedPerformancePoints() {
- if (mPerformancePoints == null) {
- return null;
- }
- return new ArrayList<PerformancePoint>(mPerformancePoints);
+ return mPerformancePoints;
}
/**
@@ -1945,7 +2096,7 @@
mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
}
- private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
+ private @Nullable List<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
Vector<PerformancePoint> ret = new Vector<>();
final String prefix = "performance-point-";
Set<String> keys = map.keySet();
@@ -1959,7 +2110,7 @@
// This means that component knowingly did not publish performance points.
// This is different from when the component forgot to publish performance
// points.
- return ret;
+ return Collections.unmodifiableList(ret);
}
String[] temp = key.split("-");
if (temp.length != 4) {
@@ -1974,23 +2125,32 @@
if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
continue;
}
- ret.add(new PerformancePoint(
+ PerformancePoint given = new PerformancePoint(
size.getWidth(), size.getHeight(), range.getLower().intValue(),
- range.getUpper().intValue()));
+ range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
+ PerformancePoint rotated = new PerformancePoint(
+ size.getHeight(), size.getWidth(), range.getLower().intValue(),
+ range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight));
+ ret.add(given);
+ if (!given.covers(rotated)) {
+ ret.add(rotated);
+ }
}
+
// check if the component specified no performance point indication
if (ret.size() == 0) {
return null;
}
// sort reversed by area first, then by frame rate
- ret.sort((a, b) -> -((a.macroBlocks != b.macroBlocks) ?
- (a.macroBlocks < b.macroBlocks ? -1 : 1) :
- (a.macroBlockRate != b.macroBlockRate) ?
- (a.macroBlockRate < b.macroBlockRate ? -1 : 1) :
- (a.frameRate != b.frameRate) ?
- (a.frameRate < b.frameRate ? -1 : 1) : 0));
- return ret;
+ ret.sort((a, b) ->
+ -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ?
+ (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) :
+ (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ?
+ (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
+ (a.getMaxFrameRate() != b.getMaxFrameRate()) ?
+ (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
+ return Collections.unmodifiableList(ret);
}
private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
@@ -3223,14 +3383,83 @@
// These constants were originally in-line with OMX values, but this
// correspondence is no longer maintained.
+ // Profiles and levels for AVC Codec, corresponding to the definitions in
+ // "SERIES H: AUDIOVISUAL AND MULTIMEDIA SYSTEMS,
+ // Infrastructure of audiovisual services – Coding of moving video
+ // Advanced video coding for generic audiovisual services"
+ // found at
+ // https://www.itu.int/rec/T-REC-H.264-201704-I
+
+ /**
+ * AVC Baseline profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileBaseline = 0x01;
+
+ /**
+ * AVC Main profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileMain = 0x02;
+
+ /**
+ * AVC Extended profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileExtended = 0x04;
+
+ /**
+ * AVC High profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileHigh = 0x08;
+
+ /**
+ * AVC High 10 profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileHigh10 = 0x10;
+
+ /**
+ * AVC High 4:2:2 profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileHigh422 = 0x20;
+
+ /**
+ * AVC High 4:4:4 profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileHigh444 = 0x40;
+
+ /**
+ * AVC Constrained Baseline profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileConstrainedBaseline = 0x10000;
+
+ /**
+ * AVC Constrained High profile.
+ * See definition in
+ * <a href="https://www.itu.int/rec/T-REC-H.264-201704-I">H.264 recommendation</a>,
+ * Annex A.
+ */
public static final int AVCProfileConstrainedHigh = 0x80000;
public static final int AVCLevel1 = 0x01;
@@ -3335,14 +3564,29 @@
public static final int VP8ProfileMain = 0x01;
+ /** VP9 Profile 0 4:2:0 8-bit */
public static final int VP9Profile0 = 0x01;
+
+ /** VP9 Profile 1 4:2:2 8-bit */
public static final int VP9Profile1 = 0x02;
+
+ /** VP9 Profile 2 4:2:0 10-bit */
public static final int VP9Profile2 = 0x04;
+
+ /** VP9 Profile 3 4:2:2 10-bit */
public static final int VP9Profile3 = 0x08;
+
// HDR profiles also support passing HDR metadata
+ /** VP9 Profile 2 4:2:0 10-bit HDR */
public static final int VP9Profile2HDR = 0x1000;
+
+ /** VP9 Profile 3 4:2:2 10-bit HDR */
public static final int VP9Profile3HDR = 0x2000;
+
+ /** VP9 Profile 2 4:2:0 10-bit HDR10Plus */
public static final int VP9Profile2HDR10Plus = 0x4000;
+
+ /** VP9 Profile 3 4:2:2 10-bit HDR10Plus */
public static final int VP9Profile3HDR10Plus = 0x8000;
public static final int VP9Level1 = 0x1;
@@ -3420,9 +3664,34 @@
public static final int DolbyVisionLevelUhd48 = 0x80;
public static final int DolbyVisionLevelUhd60 = 0x100;
- public static final int AV1Profile0 = 0x1;
- public static final int AV1Profile1 = 0x2;
- public static final int AV1Profile2 = 0x4;
+ // Profiles and levels for AV1 Codec, corresponding to the definitions in
+ // "AV1 Bitstream & Decoding Process Specification", Annex A
+ // found at https://aomedia.org/av1-bitstream-and-decoding-process-specification/
+
+ /**
+ * AV1 Main profile 4:2:0 8-bit
+ *
+ * See definition in
+ * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
+ * Annex A.
+ */
+ public static final int AV1ProfileMain8 = 0x1;
+
+ /**
+ * AV1 Main profile 4:2:0 10-bit
+ *
+ * See definition in
+ * <a href="https://aomedia.org/av1-bitstream-and-decoding-process-specification/">AV1 Specification</a>
+ * Annex A.
+ */
+ public static final int AV1ProfileMain10 = 0x2;
+
+
+ /** AV1 Main profile 4:2:0 10-bit with HDR10. */
+ public static final int AV1ProfileMain10HDR10 = 0x1000;
+
+ /** AV1 Main profile 4:2:0 10-bit with HDR10Plus. */
+ public static final int AV1ProfileMain10HDR10Plus = 0x2000;
public static final int AV1Level2 = 0x1;
public static final int AV1Level21 = 0x2;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 2c53d8c..aeb77cf 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -1363,6 +1363,17 @@
removeAllSecureStops();;
}
+ /**
+ * @deprecated Not of any use for application development;
+ * please note that the related integer constants remain supported:
+ * {@link #HDCP_LEVEL_UNKNOWN},
+ * {@link #HDCP_NONE},
+ * {@link #HDCP_V1},
+ * {@link #HDCP_V2},
+ * {@link #HDCP_V2_1},
+ * {@link #HDCP_V2_2},
+ * {@link #HDCP_V2_3}
+ */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@IntDef({HDCP_LEVEL_UNKNOWN, HDCP_NONE, HDCP_V1, HDCP_V2,
@@ -1456,6 +1467,15 @@
/**
* Security level indicates the robustness of the device's DRM
* implementation.
+ *
+ * @deprecated Not of any use for application development;
+ * please note that the related integer constants remain supported:
+ * {@link #SECURITY_LEVEL_UNKNOWN},
+ * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO},
+ * {@link #SECURITY_LEVEL_SW_SECURE_DECODE},
+ * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO},
+ * {@link #SECURITY_LEVEL_HW_SECURE_DECODE},
+ * {@link #SECURITY_LEVEL_HW_SECURE_ALL}
*/
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@@ -1568,13 +1588,13 @@
* {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
*/
@NonNull
- public native String getPropertyString(@NonNull @StringProperty String propertyName);
+ public native String getPropertyString(@NonNull String propertyName);
/**
* Set a MediaDrm String property value, given the property name string
* and new value for the property.
*/
- public native void setPropertyString(@NonNull @StringProperty String propertyName,
+ public native void setPropertyString(@NonNull String propertyName,
@NonNull String value);
/**
@@ -1596,14 +1616,14 @@
* Standard fields names are {@link #PROPERTY_DEVICE_UNIQUE_ID}
*/
@NonNull
- public native byte[] getPropertyByteArray(@ArrayProperty String propertyName);
+ public native byte[] getPropertyByteArray(String propertyName);
/**
* Set a MediaDrm byte array property value, given the property name string
* and new value for the property.
*/
- public native void setPropertyByteArray(@NonNull @ArrayProperty
- String propertyName, @NonNull byte[] value);
+ public native void setPropertyByteArray(
+ @NonNull String propertyName, @NonNull byte[] value);
private static final native void setCipherAlgorithmNative(
@NonNull MediaDrm drm, @NonNull byte[] sessionId, @NonNull String algorithm);
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 12e02e7..27499c6 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1036,6 +1036,15 @@
*/
public static final String KEY_CA_PRIVATE_DATA = "ca-private-data";
+ /**
+ * A key describing the maximum number of B frames between I or P frames,
+ * to be used by a video encoder.
+ * The associated value is an integer. The default value is 0, which means
+ * that no B frames are allowed. Note that non-zero value does not guarantee
+ * B frames; it's up to the encoder to decide.
+ */
+ public static final String KEY_MAX_BFRAMES = "max-bframes";
+
/* package private */ MediaFormat(@NonNull Map<String, Object> map) {
mMap = map;
}
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index d724762..3838a999 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -37,6 +37,7 @@
import java.net.UnknownServiceException;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
/** @hide */
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
@@ -46,27 +47,23 @@
// connection timeout - 30 sec
private static final int CONNECT_TIMEOUT_MS = 30 * 1000;
- @UnsupportedAppUsage
- private long mCurrentOffset = -1;
- @UnsupportedAppUsage
- private URL mURL = null;
- @UnsupportedAppUsage
- private Map<String, String> mHeaders = null;
- @UnsupportedAppUsage
- private HttpURLConnection mConnection = null;
- @UnsupportedAppUsage
- private long mTotalSize = -1;
- private InputStream mInputStream = null;
-
- @UnsupportedAppUsage
- private boolean mAllowCrossDomainRedirect = true;
- @UnsupportedAppUsage
- private boolean mAllowCrossProtocolRedirect = true;
-
// from com.squareup.okhttp.internal.http
private final static int HTTP_TEMP_REDIRECT = 307;
private final static int MAX_REDIRECTS = 20;
+ class ConnectionState {
+ public HttpURLConnection mConnection = null;
+ public InputStream mInputStream = null;
+ public long mCurrentOffset = -1;
+ public Map<String, String> mHeaders = null;
+ public URL mURL = null;
+ public long mTotalSize = -1;
+ public boolean mAllowCrossDomainRedirect = true;
+ public boolean mAllowCrossProtocolRedirect = true;
+ }
+ private final AtomicReference<ConnectionState> mConnectionStateHolder =
+ new AtomicReference<ConnectionState>();
+
@UnsupportedAppUsage
public MediaHTTPConnection() {
CookieHandler cookieHandler = CookieHandler.getDefault();
@@ -84,13 +81,23 @@
Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
}
+ ConnectionState connectionState = mConnectionStateHolder.get();
+ synchronized (this) {
+ if (connectionState == null) {
+ connectionState = new ConnectionState();
+ mConnectionStateHolder.set(connectionState);
+ }
+ }
+
try {
disconnect();
- mAllowCrossDomainRedirect = true;
- mURL = new URL(uri);
- mHeaders = convertHeaderStringToMap(headers);
+ connectionState.mAllowCrossDomainRedirect = true;
+ connectionState.mURL = new URL(uri);
+ connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState);
} catch (MalformedURLException e) {
return null;
+ } finally {
+ mConnectionStateHolder.set(connectionState);
}
return native_getIMemory();
@@ -106,18 +113,21 @@
}
/* returns true iff header is internal */
- private boolean filterOutInternalHeaders(String key, String val) {
+ private boolean filterOutInternalHeaders(
+ String key, String val, ConnectionState connectionState) {
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
- mAllowCrossDomainRedirect = parseBoolean(val);
+ connectionState.mAllowCrossDomainRedirect = parseBoolean(val);
// cross-protocol redirects are also controlled by this flag
- mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
+ connectionState.mAllowCrossProtocolRedirect =
+ connectionState.mAllowCrossDomainRedirect;
} else {
return false;
}
return true;
}
- private Map<String, String> convertHeaderStringToMap(String headers) {
+ private Map<String, String> convertHeaderStringToMap(String headers,
+ ConnectionState connectionState) {
HashMap<String, String> map = new HashMap<String, String>();
String[] pairs = headers.split("\r\n");
@@ -127,7 +137,7 @@
String key = pair.substring(0, colonPos);
String val = pair.substring(colonPos + 1);
- if (!filterOutInternalHeaders(key, val)) {
+ if (!filterOutInternalHeaders(key, val, connectionState)) {
map.put(key, val);
}
}
@@ -139,25 +149,28 @@
@Override
@UnsupportedAppUsage
public void disconnect() {
- teardownConnection();
- mHeaders = null;
- mURL = null;
+ ConnectionState connectionState = mConnectionStateHolder.getAndSet(null);
+ if (connectionState != null) {
+ teardownConnection(connectionState);
+ connectionState.mHeaders = null;
+ connectionState.mURL = null;
+ }
}
- private void teardownConnection() {
- if (mConnection != null) {
- if (mInputStream != null) {
+ private void teardownConnection(ConnectionState connectionState) {
+ if (connectionState.mConnection != null) {
+ if (connectionState.mInputStream != null) {
try {
- mInputStream.close();
+ connectionState.mInputStream.close();
} catch (IOException e) {
}
- mInputStream = null;
+ connectionState.mInputStream = null;
}
- mConnection.disconnect();
- mConnection = null;
+ connectionState.mConnection.disconnect();
+ connectionState.mConnection = null;
- mCurrentOffset = -1;
+ connectionState.mCurrentOffset = -1;
}
}
@@ -184,42 +197,44 @@
return false;
}
- private void seekTo(long offset) throws IOException {
- teardownConnection();
+ private void seekTo(long offset, ConnectionState connectionState) throws IOException {
+ teardownConnection(connectionState);
try {
int response;
int redirectCount = 0;
- URL url = mURL;
+ URL url = connectionState.mURL;
// do not use any proxy for localhost (127.0.0.1)
boolean noProxy = isLocalHost(url);
while (true) {
if (noProxy) {
- mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+ connectionState.mConnection =
+ (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
} else {
- mConnection = (HttpURLConnection)url.openConnection();
+ connectionState.mConnection = (HttpURLConnection) url.openConnection();
}
- mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
+ connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
// handle redirects ourselves if we do not allow cross-domain redirect
- mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
+ connectionState.mConnection.setInstanceFollowRedirects(
+ connectionState.mAllowCrossDomainRedirect);
- if (mHeaders != null) {
- for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
- mConnection.setRequestProperty(
+ if (connectionState.mHeaders != null) {
+ for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) {
+ connectionState.mConnection.setRequestProperty(
entry.getKey(), entry.getValue());
}
}
if (offset > 0) {
- mConnection.setRequestProperty(
+ connectionState.mConnection.setRequestProperty(
"Range", "bytes=" + offset + "-");
}
- response = mConnection.getResponseCode();
+ response = connectionState.mConnection.getResponseCode();
if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
response != HttpURLConnection.HTTP_MOVED_PERM &&
response != HttpURLConnection.HTTP_MOVED_TEMP &&
@@ -233,7 +248,7 @@
throw new NoRouteToHostException("Too many redirects: " + redirectCount);
}
- String method = mConnection.getRequestMethod();
+ String method = connectionState.mConnection.getRequestMethod();
if (response == HTTP_TEMP_REDIRECT &&
!method.equals("GET") && !method.equals("HEAD")) {
// "If the 307 status code is received in response to a
@@ -241,34 +256,35 @@
// automatically redirect the request"
throw new NoRouteToHostException("Invalid redirect");
}
- String location = mConnection.getHeaderField("Location");
+ String location = connectionState.mConnection.getHeaderField("Location");
if (location == null) {
throw new NoRouteToHostException("Invalid redirect");
}
- url = new URL(mURL /* TRICKY: don't use url! */, location);
+ url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location);
if (!url.getProtocol().equals("https") &&
!url.getProtocol().equals("http")) {
throw new NoRouteToHostException("Unsupported protocol redirect");
}
- boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
- if (!mAllowCrossProtocolRedirect && !sameProtocol) {
+ boolean sameProtocol =
+ connectionState.mURL.getProtocol().equals(url.getProtocol());
+ if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) {
throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
}
- boolean sameHost = mURL.getHost().equals(url.getHost());
- if (!mAllowCrossDomainRedirect && !sameHost) {
+ boolean sameHost = connectionState.mURL.getHost().equals(url.getHost());
+ if (!connectionState.mAllowCrossDomainRedirect && !sameHost) {
throw new NoRouteToHostException("Cross-domain redirects are disallowed");
}
if (response != HTTP_TEMP_REDIRECT) {
// update effective URL, unless it is a Temporary Redirect
- mURL = url;
+ connectionState.mURL = url;
}
}
- if (mAllowCrossDomainRedirect) {
+ if (connectionState.mAllowCrossDomainRedirect) {
// remember the current, potentially redirected URL if redirects
// were handled by HttpURLConnection
- mURL = mConnection.getURL();
+ connectionState.mURL = connectionState.mConnection.getURL();
}
if (response == HttpURLConnection.HTTP_PARTIAL) {
@@ -276,10 +292,9 @@
// because what we want is not just the length of the range
// returned but the size of the full content if available.
- String contentRange =
- mConnection.getHeaderField("Content-Range");
+ String contentRange = connectionState.mConnection.getHeaderField("Content-Range");
- mTotalSize = -1;
+ connectionState.mTotalSize = -1;
if (contentRange != null) {
// format is "bytes xxx-yyy/zzz
// where "zzz" is the total number of bytes of the
@@ -291,7 +306,7 @@
contentRange.substring(lastSlashPos + 1);
try {
- mTotalSize = Long.parseLong(total);
+ connectionState.mTotalSize = Long.parseLong(total);
} catch (NumberFormatException e) {
}
}
@@ -299,7 +314,7 @@
} else if (response != HttpURLConnection.HTTP_OK) {
throw new IOException();
} else {
- mTotalSize = mConnection.getContentLength();
+ connectionState.mTotalSize = connectionState.mConnection.getContentLength();
}
if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
@@ -308,14 +323,14 @@
throw new ProtocolException();
}
- mInputStream =
- new BufferedInputStream(mConnection.getInputStream());
+ connectionState.mInputStream =
+ new BufferedInputStream(connectionState.mConnection.getInputStream());
- mCurrentOffset = offset;
+ connectionState.mCurrentOffset = offset;
} catch (IOException e) {
- mTotalSize = -1;
- teardownConnection();
- mCurrentOffset = -1;
+ connectionState.mTotalSize = -1;
+ teardownConnection(connectionState);
+ connectionState.mCurrentOffset = -1;
throw e;
}
@@ -324,10 +339,14 @@
@Override
@UnsupportedAppUsage
public int readAt(long offset, int size) {
- return native_readAt(offset, size);
+ ConnectionState connectionState = mConnectionStateHolder.get();
+ if (connectionState != null) {
+ return native_readAt(offset, size, connectionState);
+ }
+ return -1;
}
- private int readAt(long offset, byte[] data, int size) {
+ private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
@@ -335,12 +354,12 @@
try {
synchronized(this) {
- if (offset != mCurrentOffset) {
- seekTo(offset);
+ if (offset != connectionState.mCurrentOffset) {
+ seekTo(offset, connectionState);
}
}
- int n = mInputStream.read(data, 0, size);
+ int n = connectionState.mInputStream.read(data, 0, size);
if (n == -1) {
// InputStream signals EOS using a -1 result, our semantics
@@ -348,7 +367,7 @@
n = 0;
}
- mCurrentOffset += n;
+ connectionState.mCurrentOffset += n;
if (VERBOSE) {
Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
@@ -380,35 +399,47 @@
@Override
public synchronized long getSize() {
- if (mConnection == null) {
- try {
- seekTo(0);
- } catch (IOException e) {
- return -1;
+ ConnectionState connectionState = mConnectionStateHolder.get();
+ if (connectionState != null) {
+ if (connectionState.mConnection == null) {
+ try {
+ seekTo(0, connectionState);
+ } catch (IOException e) {
+ return -1;
+ }
}
+ return connectionState.mTotalSize;
}
- return mTotalSize;
+ return -1;
}
@Override
@UnsupportedAppUsage
public synchronized String getMIMEType() {
- if (mConnection == null) {
- try {
- seekTo(0);
- } catch (IOException e) {
- return "application/octet-stream";
+ ConnectionState connectionState = mConnectionStateHolder.get();
+ if (connectionState != null) {
+ if (connectionState.mConnection == null) {
+ try {
+ seekTo(0, connectionState);
+ } catch (IOException e) {
+ return "application/octet-stream";
+ }
}
+ return connectionState.mConnection.getContentType();
}
- return mConnection.getContentType();
+ return null;
}
@Override
@UnsupportedAppUsage
public String getUri() {
- return mURL.toString();
+ ConnectionState connectionState = mConnectionStateHolder.get();
+ if (connectionState != null) {
+ return connectionState.mURL.toString();
+ }
+ return null;
}
@Override
@@ -421,7 +452,7 @@
private native final void native_finalize();
private native final IBinder native_getIMemory();
- private native final int native_readAt(long offset, int size);
+ private native int native_readAt(long offset, int size, ConnectionState connectionState);
static {
System.loadLibrary("media_jni");
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index abbfa88..040152a 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2645,7 +2645,7 @@
*/
private synchronized void setSubtitleAnchor() {
if ((mSubtitleController == null) && (ActivityThread.currentApplication() != null)) {
- getMediaTimeProvider();
+ final TimeProvider timeProvider = (TimeProvider) getMediaTimeProvider();
final HandlerThread thread = new HandlerThread("SetSubtitleAnchorThread");
thread.start();
Handler handler = new Handler(thread.getLooper());
@@ -2653,7 +2653,8 @@
@Override
public void run() {
Context context = ActivityThread.currentApplication();
- mSubtitleController = new SubtitleController(context, mTimeProvider, MediaPlayer.this);
+ mSubtitleController =
+ new SubtitleController(context, timeProvider, MediaPlayer.this);
mSubtitleController.setAnchor(new Anchor() {
@Override
public void setSubtitleWidget(RenderingWidget subtitleWidget) {
@@ -2661,7 +2662,7 @@
@Override
public Looper getSubtitleLooper() {
- return mTimeProvider.mEventHandler.getLooper();
+ return timeProvider.mEventHandler.getLooper();
}
});
thread.getLooper().quitSafely();
diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java
index da3362a..0777ba3 100644
--- a/media/java/android/media/MediaTimestamp.java
+++ b/media/java/android/media/MediaTimestamp.java
@@ -16,8 +16,7 @@
package android.media;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
+import android.annotation.FloatRange;
/**
* An immutable object that represents the linear correlation between the media time
@@ -76,6 +75,7 @@
* greater than 1.0 if media clock is faster than the system clock;
* less than 1.0 if media clock is slower than the system clock.
*/
+ @FloatRange(from = 0.0f, to = Float.MAX_VALUE)
public float getMediaClockRate() {
return clockRate;
}
@@ -87,11 +87,19 @@
/** @hide - accessor shorthand */
public final float clockRate;
- /** @hide */
- MediaTimestamp(long mediaUs, long systemNs, float rate) {
- mediaTimeUs = mediaUs;
- nanoTime = systemNs;
- clockRate = rate;
+ /**
+ * Constructor.
+ *
+ * @param mediaTimeUs the media time of the anchor in microseconds
+ * @param nanoTimeNs the {@link java.lang.System#nanoTime system time} corresponding to the
+ * media time in nanoseconds.
+ * @param clockRate the rate of the media clock in relation to the system time.
+ */
+ public MediaTimestamp(long mediaTimeUs, long nanoTimeNs,
+ @FloatRange(from = 0.0f, to = Float.MAX_VALUE) float clockRate) {
+ this.mediaTimeUs = mediaTimeUs;
+ this.nanoTime = nanoTimeNs;
+ this.clockRate = clockRate;
}
/** @hide */
@@ -120,71 +128,4 @@
+ " clockRate=" + clockRate
+ "}";
}
-
- /**
- * Builder class for {@link MediaTimestamp} objects.
- * <p> Here is an example where <code>Builder</code> is used to define the
- * {@link MediaTimestamp}:
- *
- * <pre class="prettyprint">
- * MediaTimestamp mts = new MediaTimestamp.Builder()
- * .setMediaTimestamp(mediaTime, systemTime, rate)
- * .build();
- * </pre>
- * @hide
- */
- @SystemApi
- public static final class Builder {
- long mMediaTimeUs;
- long mNanoTime;
- float mClockRate = 1.0f;
-
- /**
- * Constructs a new Builder with the defaults.
- */
- public Builder() {
- }
-
- /**
- * Constructs a new Builder from a given {@link MediaTimestamp} instance
- * @param mts the {@link MediaTimestamp} object whose data will be reused
- * in the new Builder.
- */
- public Builder(@NonNull MediaTimestamp mts) {
- if (mts == null) {
- throw new IllegalArgumentException("null MediaTimestamp is not allowed");
- }
- mMediaTimeUs = mts.mediaTimeUs;
- mNanoTime = mts.nanoTime;
- mClockRate = mts.clockRate;
- }
-
- /**
- * Combines all of the fields that have been set and return a new
- * {@link MediaTimestamp} object.
- *
- * @return a new {@link MediaTimestamp} object
- */
- public @NonNull MediaTimestamp build() {
- return new MediaTimestamp(mMediaTimeUs, mNanoTime, mClockRate);
- }
-
- /**
- * Sets the info of media timestamp.
- *
- * @param mediaTimeUs the media time of the anchor in microseconds
- * @param nanoTime the {@link java.lang.System#nanoTime system time} corresponding to
- * the media time in nanoseconds.
- * @param clockRate the rate of the media clock in relation to the system time.
- * @return the same Builder instance.
- */
- public @NonNull Builder setMediaTimestamp(
- long mediaTimeUs, long nanoTime, float clockRate) {
- mMediaTimeUs = mediaTimeUs;
- mNanoTime = nanoTime;
- mClockRate = clockRate;
-
- return this;
- }
- }
}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 0679e8e9..9a60923 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -215,17 +215,19 @@
// Make sure the column ordering and then ..._COLUMN_INDEX are in sync
private static final String[] INTERNAL_COLUMNS = new String[] {
- MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
- "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"",
- MediaStore.Audio.Media.TITLE_KEY
+ MediaStore.Audio.Media._ID,
+ MediaStore.Audio.Media.TITLE,
+ MediaStore.Audio.Media.TITLE,
+ MediaStore.Audio.Media.TITLE_KEY,
};
private static final String[] MEDIA_COLUMNS = new String[] {
- MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE,
- "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"",
- MediaStore.Audio.Media.TITLE_KEY
+ MediaStore.Audio.Media._ID,
+ MediaStore.Audio.Media.TITLE,
+ MediaStore.Audio.Media.TITLE,
+ MediaStore.Audio.Media.TITLE_KEY,
};
-
+
/**
* The column index (in the cursor returned by {@link #getCursor()} for the
* row ID.
@@ -459,8 +461,9 @@
// We don't need to re-add the internal ringtones for the work profile since
// they are the same as the personal profile. We just need the external
// ringtones.
- return new ExternalRingtonesCursorWrapper(getMediaRingtones(parentContext),
- parentInfo.id);
+ final Cursor res = getMediaRingtones(parentContext);
+ return new ExternalRingtonesCursorWrapper(res, ContentProvider.maybeAddUserId(
+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, parentInfo.id));
}
}
return null;
@@ -580,14 +583,16 @@
@UnsupportedAppUsage
private Cursor getInternalRingtones() {
- return query(
+ final Cursor res = query(
MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS,
constructBooleanTrueWhereClause(mFilterColumns),
null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
+ return new ExternalRingtonesCursorWrapper(res, MediaStore.Audio.Media.INTERNAL_CONTENT_URI);
}
private Cursor getMediaRingtones() {
- return getMediaRingtones(mContext);
+ final Cursor res = getMediaRingtones(mContext);
+ return new ExternalRingtonesCursorWrapper(res, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
}
@UnsupportedAppUsage
diff --git a/media/java/android/media/SRTRenderer.java b/media/java/android/media/SRTRenderer.java
index a3e2abd..505f996 100644
--- a/media/java/android/media/SRTRenderer.java
+++ b/media/java/android/media/SRTRenderer.java
@@ -125,6 +125,7 @@
String[] startEnd = header.split("-->");
cue.mStartTimeMs = parseMs(startEnd[0]);
cue.mEndTimeMs = parseMs(startEnd[1]);
+ cue.mRunID = runID;
String s;
List<String> paragraph = new ArrayList<String>();
diff --git a/media/java/android/media/SubtitleData.java b/media/java/android/media/SubtitleData.java
index 2c6c61f..2ef6982 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -17,11 +17,8 @@
package android.media;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
-import java.util.Arrays;
-
/**
* Class encapsulating subtitle data, as received through the
* {@link MediaPlayer.OnSubtitleDataListener} interface.
@@ -82,12 +79,23 @@
}
}
- /** @hide */
+ /**
+ * Constructor.
+ *
+ * @param trackIndex the index of the media player track which contains this subtitle data.
+ * @param startTimeUs the start time in microsecond for the subtitle data
+ * @param durationUs the duration in microsecond for the subtitle data
+ * @param data the data array for the subtitle data. It should not be null.
+ * No data copying is made.
+ */
public SubtitleData(int trackIndex, long startTimeUs, long durationUs, @NonNull byte[] data) {
+ if (data == null) {
+ throw new IllegalArgumentException("null data is not allowed");
+ }
mTrackIndex = trackIndex;
mStartTimeUs = startTimeUs;
mDurationUs = durationUs;
- mData = (data != null ? data : new byte[0]);
+ mData = data;
}
/**
@@ -141,80 +149,4 @@
return true;
}
-
- /**
- * Builder class for {@link SubtitleData} objects.
- * <p> Here is an example where <code>Builder</code> is used to define the
- * {@link SubtitleData}:
- *
- * <pre class="prettyprint">
- * SubtitleData sd = new SubtitleData.Builder()
- * .setSubtitleData(trackIndex, startTime, duration, data)
- * .build();
- * </pre>
- * @hide
- */
- @SystemApi
- public static final class Builder {
- private int mTrackIndex;
- private long mStartTimeUs;
- private long mDurationUs;
- private byte[] mData = new byte[0];
-
- /**
- * Constructs a new Builder with the defaults.
- */
- public Builder() {
- }
-
- /**
- * Constructs a new Builder from a given {@link SubtitleData} instance
- * @param sd the {@link SubtitleData} object whose data will be reused
- * in the new Builder. It should not be null. The data array is copied.
- */
- public Builder(@NonNull SubtitleData sd) {
- if (sd == null) {
- throw new IllegalArgumentException("null SubtitleData is not allowed");
- }
- mTrackIndex = sd.mTrackIndex;
- mStartTimeUs = sd.mStartTimeUs;
- mDurationUs = sd.mDurationUs;
- if (sd.mData != null) {
- mData = Arrays.copyOf(sd.mData, sd.mData.length);
- }
- }
-
- /**
- * Combines all of the fields that have been set and return a new
- * {@link SubtitleData} object. <code>IllegalStateException</code> will be
- * thrown if there is conflict between fields.
- *
- * @return a new {@link SubtitleData} object
- */
- public @NonNull SubtitleData build() {
- return new SubtitleData(mTrackIndex, mStartTimeUs, mDurationUs, mData);
- }
-
- /**
- * Sets the info of subtitle data.
- *
- * @param trackIndex the index of the media player track which contains this subtitle data.
- * @param startTimeUs the start time in microsecond for the subtile data
- * @param durationUs the duration in microsecond for the subtile data
- * @param data the data array for the subtile data. It should not be null.
- * No data copying is made.
- * @return the same Builder instance.
- */
- public @NonNull Builder setSubtitleData(
- int trackIndex, long startTimeUs, long durationUs, @NonNull byte[] data) {
- if (data == null) {
- throw new IllegalArgumentException("null data is not allowed");
- }
- mTrackIndex = trackIndex;
- mStartTimeUs = startTimeUs;
- mDurationUs = durationUs;
- mData = data;
- return this;
- }
- }
}
diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java
index 5596c32..0705d97 100644
--- a/media/java/android/media/SubtitleTrack.java
+++ b/media/java/android/media/SubtitleTrack.java
@@ -263,7 +263,9 @@
}
updateView(mActiveCues);
mNextScheduledTimeMs = -1;
- mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+ if (mTimeProvider != null) {
+ mTimeProvider.notifyAt(MediaTimeProvider.NO_TIME, this);
+ }
}
/** @hide */
diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java
index 990760c..b99b30c 100644
--- a/media/java/android/media/TimedMetaData.java
+++ b/media/java/android/media/TimedMetaData.java
@@ -17,11 +17,8 @@
package android.media;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.os.Parcel;
-import java.util.Arrays;
-
/**
* Class that embodies one timed metadata access unit, including
*
@@ -52,7 +49,11 @@
}
/**
- * @hide
+ * Constructor.
+ *
+ * @param timestampUs the timestamp in microsecond for the timed metadata
+ * @param metaData the metadata array for the timed metadata. No data copying is made.
+ * It should not be null.
*/
public TimedMetaData(long timestampUs, @NonNull byte[] metaData) {
if (metaData == null) {
@@ -90,71 +91,4 @@
return true;
}
-
- /**
- * Builder class for {@link TimedMetaData} objects.
- * <p> Here is an example where <code>Builder</code> is used to define the
- * {@link TimedMetaData}:
- *
- * <pre class="prettyprint">
- * TimedMetaData tmd = new TimedMetaData.Builder()
- * .setTimedMetaData(timestamp, metaData)
- * .build();
- * </pre>
- * @hide
- */
- @SystemApi
- public static final class Builder {
- private long mTimestampUs;
- private byte[] mMetaData = new byte[0];
-
- /**
- * Constructs a new Builder with the defaults.
- */
- public Builder() {
- }
-
- /**
- * Constructs a new Builder from a given {@link TimedMetaData} instance
- * @param tmd the {@link TimedMetaData} object whose data will be reused
- * in the new Builder. It should not be null. The metadata array is copied.
- */
- public Builder(@NonNull TimedMetaData tmd) {
- if (tmd == null) {
- throw new IllegalArgumentException("null TimedMetaData is not allowed");
- }
- mTimestampUs = tmd.mTimestampUs;
- if (tmd.mMetaData != null) {
- mMetaData = Arrays.copyOf(tmd.mMetaData, tmd.mMetaData.length);
- }
- }
-
- /**
- * Combines all of the fields that have been set and return a new
- * {@link TimedMetaData} object. <code>IllegalStateException</code> will be
- * thrown if there is conflict between fields.
- *
- * @return a new {@link TimedMetaData} object
- */
- public @NonNull TimedMetaData build() {
- return new TimedMetaData(mTimestampUs, mMetaData);
- }
-
- /**
- * Sets the info of timed metadata.
- *
- * @param timestamp the timestamp in microsecond for the timed metadata
- * @param metaData the metadata array for the timed metadata. No data copying is made.
- * It should not be null.
- * @return the same Builder instance.
- */
- public @NonNull Builder setTimedMetaData(long timestamp, @NonNull byte[] metaData) {
- if (metaData == null) {
- throw new IllegalArgumentException("null metaData is not allowed");
- }
- mTimestampUs = timestamp;
- mMetaData = metaData;
- return this;
- }
- }
}
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index 6c48cdb..d41f416 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -409,6 +409,10 @@
final int match_rule = rule & ~RULE_EXCLUSION_MASK;
while (crIterator.hasNext()) {
final AudioMixMatchCriterion criterion = crIterator.next();
+
+ if ((criterion.mRule & ~RULE_EXCLUSION_MASK) != match_rule) {
+ continue; // The two rules are not of the same type
+ }
switch (match_rule) {
case RULE_MATCH_ATTRIBUTE_USAGE:
// "usage"-based rule
diff --git a/media/java/android/media/session/ControllerLink.aidl b/media/java/android/media/session/ControllerLink.aidl
deleted file mode 100644
index 532df59..0000000
--- a/media/java/android/media/session/ControllerLink.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 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 android.media.session;
-
-parcelable ControllerLink;
diff --git a/media/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java
deleted file mode 100644
index d4ea2a3..0000000
--- a/media/java/android/media/session/ControllerLink.java
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * Copyright 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 android.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.session.MediaController.PlaybackInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Handles incoming commands from {@link MediaController}.
- * @hide
- */
-public final class ControllerLink implements Parcelable {
- public static final @android.annotation.NonNull Parcelable.Creator<ControllerLink> CREATOR =
- new Parcelable.Creator<ControllerLink>() {
- @Override
- public ControllerLink createFromParcel(Parcel in) {
- return new ControllerLink(in.readStrongBinder());
- }
-
- @Override
- public ControllerLink[] newArray(int size) {
- return new ControllerLink[size];
- }
- };
-
- final ControllerStub mControllerStub;
- final ISessionController mISessionController;
-
- /**
- * Constructor for stub (Callee)
- */
- public ControllerLink(@NonNull ControllerStub controllerStub) {
- mControllerStub = controllerStub;
- mISessionController = new StubProxy();
- }
-
- /**
- * Constructor for interface (Caller)
- */
- public ControllerLink(IBinder binder) {
- mControllerStub = null;
- mISessionController = ISessionController.Stub.asInterface(binder);
- }
-
- /**
- * Tell system that a controller sends a command.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param command the name of the command
- * @param args the arguments included with the command
- * @param cb the result receiver for getting the result of the command
- */
- void sendCommand(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {
- try {
- mISessionController.sendCommand(packageName, caller, command, args, cb);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller sends a media button event.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param mediaButton the media button key event
- */
- boolean sendMediaButton(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull KeyEvent mediaButton) {
- try {
- return mISessionController.sendMediaButton(packageName, caller, mediaButton);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Registers a controller callback link to the system.
- *
- * @param packageName the package name of the controller
- * @param cb the controller callback link to register
- */
- void registerCallback(@NonNull String packageName, @NonNull ControllerCallbackLink cb) {
- try {
- mISessionController.registerCallback(packageName, cb);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Unregisters a controller callback link from the system.
- *
- * @param cb the controller callback link to register
- */
- void unregisterCallback(@NonNull ControllerCallbackLink cb) {
- try {
- mISessionController.unregisterCallback(cb);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the package name of the connected session.
- */
- @NonNull
- String getPackageName() {
- try {
- return mISessionController.getPackageName();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the tag of the connected session.
- */
- @NonNull
- String getTag() {
- try {
- return mISessionController.getTag();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the session info of the connected session.
- */
- @Nullable
- Bundle getSessionInfo() {
- try {
- return mISessionController.getSessionInfo();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the {@link PendingIntent} for launching UI of the connected session.
- */
- @Nullable
- PendingIntent getLaunchPendingIntent() {
- try {
- return mISessionController.getLaunchPendingIntent();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the flags of the connected session.
- */
- long getFlags() {
- try {
- return mISessionController.getFlags();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the volume attributes of the connected session.
- */
- @NonNull
- PlaybackInfo getVolumeAttributes() {
- try {
- return mISessionController.getVolumeAttributes();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests adjusting the volume.
- *
- * @param packageName the package name of the controller
- * @param opPackageName the op package name of this request
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param direction the direction to adjust the volume in
- * @param flags the flags with this volume change request
- */
- void adjustVolume(@NonNull String packageName, @NonNull String opPackageName,
- @NonNull ControllerCallbackLink caller, int direction,
- int flags) {
- try {
- mISessionController.adjustVolume(packageName, opPackageName, caller, direction, flags);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests setting the volume.
- *
- * @param packageName the package name of the controller
- * @param opPackageName the op package name of this request
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param flags the flags with this volume change request
- */
- void setVolumeTo(@NonNull String packageName, @NonNull String opPackageName,
- @NonNull ControllerCallbackLink caller, int value, int flags) {
- try {
- mISessionController.setVolumeTo(packageName, opPackageName, caller, value, flags);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests preparing media.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void prepare(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.prepare(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests preparing media from given media ID.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param mediaId the ID of the media
- * @param extras the extras included with this request.
- */
- void prepareFromMediaId(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
- @Nullable Bundle extras) {
- try {
- mISessionController.prepareFromMediaId(packageName, caller, mediaId, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests preparing media from given search query.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param query the search query
- * @param extras the extras included with this request.
- */
- void prepareFromSearch(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String query,
- @Nullable Bundle extras) {
- try {
- mISessionController.prepareFromSearch(packageName, caller, query, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests preparing media from given uri.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param uri the uri of the media
- * @param extras the extras included with this request.
- */
- void prepareFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull Uri uri, @Nullable Bundle extras) {
- try {
- mISessionController.prepareFromUri(packageName, caller, uri, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests playing media.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void play(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.play(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests playing media from given media ID.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param mediaId the ID of the media
- * @param extras the extras included with this request.
- */
- void playFromMediaId(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull String mediaId, @Nullable Bundle extras) {
- try {
- mISessionController.playFromMediaId(packageName, caller, mediaId, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests playing media from given search query.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param query the search query
- * @param extras the extras included with this request.
- */
- void playFromSearch(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull String query, @Nullable Bundle extras) {
- try {
- mISessionController.playFromSearch(packageName, caller, query, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests playing media from given uri.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param uri the uri of the media
- * @param extras the extras included with this request.
- */
- void playFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull Uri uri, @Nullable Bundle extras) {
- try {
- mISessionController.playFromUri(packageName, caller, uri, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests skipping to the queue item with given ID.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param id the queue id of the item
- */
- void skipToQueueItem(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- long id) {
- try {
- mISessionController.skipToQueueItem(packageName, caller, id);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests pausing media.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void pause(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.pause(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests stopping media.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void stop(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.stop(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests skipping to the next queue item.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void next(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.next(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests skipping to the previous queue item.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void previous(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.previous(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests fast-forwarding.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void fastForward(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.fastForward(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests rewinding.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- */
- void rewind(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- try {
- mISessionController.rewind(packageName, caller);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests seeking to the specific position.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param pos the position to move to, in milliseconds
- */
- void seekTo(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- long pos) {
- try {
- mISessionController.seekTo(packageName, caller, pos);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests rating of the current media.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param rating the rating of the current media
- */
- void rate(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull Rating rating) {
- try {
- mISessionController.rate(packageName, caller, rating);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller requests changing the playback speed.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param speed the playback speed
- */
- void setPlaybackSpeed(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- float speed) {
- try {
- mISessionController.setPlaybackSpeed(packageName, caller, speed);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that a controller sends a custom action.
- *
- * @param packageName the package name of the controller
- * @param caller the {@link ControllerCallbackLink} of the controller
- * @param action the name of the action
- * @param args the arguments included with this action
- */
- void sendCustomAction(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String action, @Nullable Bundle args) {
- try {
- mISessionController.sendCustomAction(packageName, caller, action, args);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the current metadata of the connected session.
- */
- @Nullable
- public MediaMetadata getMetadata() {
- try {
- return mISessionController.getMetadata();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the current playback state of the connected session.
- */
- @Nullable
- public PlaybackState getPlaybackState() {
- try {
- return mISessionController.getPlaybackState();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the current queue of the connected session.
- */
- @Nullable
- public List<MediaSession.QueueItem> getQueue() {
- try {
- MediaParceledListSlice queue = mISessionController.getQueue();
- return queue == null ? null : queue.getList();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the current queue title of the connected session.
- */
- @Nullable
- public CharSequence getQueueTitle() {
- try {
- return mISessionController.getQueueTitle();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the current extras of the connected session.
- */
- @Nullable
- public Bundle getExtras() {
- try {
- return mISessionController.getExtras();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the current rating type of the connected session.
- */
- public int getRatingType() {
- try {
- return mISessionController.getRatingType();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Gets the binder */
- @NonNull
- public IBinder getBinder() {
- return mISessionController.asBinder();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mISessionController.asBinder());
- }
-
- @Override
- public int hashCode() {
- return mISessionController.asBinder().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!(obj instanceof ControllerLink)) {
- return false;
- }
- ControllerLink other = (ControllerLink) obj;
- return Objects.equals(getBinder(), other.getBinder());
- }
-
- /**
- * Class for Stub implementation
- */
- public abstract static class ControllerStub {
- /** Stub method for ISessionController.sendCommand */
- public void sendCommand(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull String command, @Nullable Bundle args, @Nullable ResultReceiver cb) {
- }
-
- /** Stub method for ISessionController.sendMediaButton */
- public boolean sendMediaButton(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull KeyEvent mediaButton) {
- return false;
- }
-
- /** Stub method for ISessionController.registerCallback */
- public void registerCallback(@NonNull String packageName,
- @NonNull ControllerCallbackLink cb) {
- }
-
- /** Stub method for ISessionController.unregisterCallback */
- public void unregisterCallback(@NonNull ControllerCallbackLink cb) {
- }
-
- /** Stub method for ISessionController.getPackageName */
- @NonNull
- public String getPackageName() {
- return null;
- }
-
- /** Stub method for ISessionController.getTag */
- @NonNull
- public String getTag() {
- return null;
- }
-
- /** Stub method for ISessionController.getSessionInfo */
- @Nullable
- public Bundle getSessionInfo() {
- return null;
- }
-
- /** Stub method for ISessionController.getLaunchPendingIntent */
- @Nullable
- public PendingIntent getLaunchPendingIntent() {
- return null;
- }
-
- /** Stub method for ISessionController.getFlags */
- public long getFlags() {
- return 0;
- }
-
- /** Stub method for ISessionController.getVolumeAttributes */
- @NonNull
- public PlaybackInfo getVolumeAttributes() {
- return null;
- }
-
- /** Stub method for ISessionController.adjustVolume */
- public void adjustVolume(@NonNull String packageName, @NonNull String opPackageName,
- @NonNull ControllerCallbackLink caller, int direction, int flags) {
- }
-
- /** Stub method for ISessionController.setVolumeTo */
- public void setVolumeTo(@NonNull String packageName, @NonNull String opPackageName,
- @NonNull ControllerCallbackLink caller, int value, int flags) {
- }
-
- /** Stub method for ISessionController.prepare */
- public void prepare(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.prepareFromMediaId */
- public void prepareFromMediaId(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
- @Nullable Bundle extras) {
- }
-
- /** Stub method for ISessionController.prepareFromSearch */
- public void prepareFromSearch(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String query,
- @Nullable Bundle extras) {
- }
-
- /** Stub method for ISessionController.prepareFromUri */
- public void prepareFromUri(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) {
- }
-
- /** Stub method for ISessionController.play */
- public void play(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.playFromMediaId */
- public void playFromMediaId(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String mediaId,
- @Nullable Bundle extras) {
- }
-
- /** Stub method for ISessionController.playFromSearch */
- public void playFromSearch(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String query,
- @Nullable Bundle extras) {
- }
-
- /** Stub method for ISessionController.playFromUri */
- public void playFromUri(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull Uri uri, @Nullable Bundle extras) {
- }
-
- /** Stub method for ISessionController.skipToQueueItem */
- public void skipToQueueItem(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, long id) {
- }
-
- /** Stub method for ISessionController.pause */
- public void pause(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.stop */
- public void stop(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.next */
- public void next(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.previous */
- public void previous(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.fastForward */
- public void fastForward(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.rewind */
- public void rewind(@NonNull String packageName, @NonNull ControllerCallbackLink caller) {
- }
-
- /** Stub method for ISessionController.seekTo */
- public void seekTo(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- long pos) {
- }
-
- /** Stub method for ISessionController.rate */
- public void rate(@NonNull String packageName, @NonNull ControllerCallbackLink caller,
- @NonNull Rating rating) {
- }
-
- /** Stub method for ISessionController.setPlaybackSpeed */
- public void setPlaybackSpeed(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, float speed) {
- }
-
- /** Stub method for ISessionController.sendCustomAction */
- public void sendCustomAction(@NonNull String packageName,
- @NonNull ControllerCallbackLink caller, @NonNull String action,
- @Nullable Bundle args) {
- }
-
- /** Stub method for ISessionController.getMetadata */
- @Nullable
- public MediaMetadata getMetadata() {
- return null;
- }
-
- /** Stub method for ISessionController.getPlaybackState */
- @Nullable
- public PlaybackState getPlaybackState() {
- return null;
- }
-
- /** Stub method for ISessionController.getQueue */
- @Nullable
- public List<MediaSession.QueueItem> getQueue() {
- return null;
- }
-
- /** Stub method for ISessionController.getQueueTitle */
- @Nullable
- public CharSequence getQueueTitle() {
- return null;
- }
-
- /** Stub method for ISessionController.getExtras */
- @Nullable
- public Bundle getExtras() {
- return null;
- }
-
- /** Stub method for ISessionController.getRatingType */
- public int getRatingType() {
- return Rating.RATING_NONE;
- }
- }
-
- private class StubProxy extends ISessionController.Stub {
- @Override
- public void sendCommand(String packageName, ControllerCallbackLink caller,
- String command, Bundle args, ResultReceiver cb) {
- mControllerStub.sendCommand(packageName, caller, command, args, cb);
- }
-
- @Override
- public boolean sendMediaButton(String packageName, ControllerCallbackLink caller,
- KeyEvent mediaButton) {
- return mControllerStub.sendMediaButton(packageName, caller, mediaButton);
- }
-
- @Override
- public void registerCallback(String packageName, ControllerCallbackLink cb) {
- mControllerStub.registerCallback(packageName, cb);
- }
-
- @Override
- public void unregisterCallback(ControllerCallbackLink cb) {
- mControllerStub.unregisterCallback(cb);
- }
-
- @Override
- public String getPackageName() {
- return mControllerStub.getPackageName();
- }
-
- @Override
- public String getTag() {
- return mControllerStub.getTag();
- }
-
- @Override
- public Bundle getSessionInfo() {
- return mControllerStub.getSessionInfo();
- }
-
- @Override
- public PendingIntent getLaunchPendingIntent() {
- return mControllerStub.getLaunchPendingIntent();
- }
-
- @Override
- public long getFlags() {
- return mControllerStub.getFlags();
- }
-
- @Override
- public PlaybackInfo getVolumeAttributes() {
- return mControllerStub.getVolumeAttributes();
- }
-
- @Override
- public void adjustVolume(String packageName, String opPackageName,
- ControllerCallbackLink caller, int direction, int flags) {
- mControllerStub.adjustVolume(packageName, opPackageName, caller, direction, flags);
- }
-
- @Override
- public void setVolumeTo(String packageName, String opPackageName,
- ControllerCallbackLink caller, int value, int flags) {
- mControllerStub.setVolumeTo(packageName, opPackageName, caller, value, flags);
- }
-
- @Override
- public void prepare(String packageName, ControllerCallbackLink caller) {
- mControllerStub.prepare(packageName, caller);
- }
-
- @Override
- public void prepareFromMediaId(String packageName, ControllerCallbackLink caller,
- String mediaId, Bundle extras) {
- mControllerStub.prepareFromMediaId(packageName, caller, mediaId, extras);
- }
-
- @Override
- public void prepareFromSearch(String packageName, ControllerCallbackLink caller,
- String query, Bundle extras) {
- mControllerStub.prepareFromSearch(packageName, caller, query, extras);
- }
-
- @Override
- public void prepareFromUri(String packageName, ControllerCallbackLink caller,
- Uri uri, Bundle extras) {
- mControllerStub.prepareFromUri(packageName, caller, uri, extras);
- }
-
- @Override
- public void play(String packageName, ControllerCallbackLink caller) {
- mControllerStub.play(packageName, caller);
- }
-
- @Override
- public void playFromMediaId(String packageName, ControllerCallbackLink caller,
- String mediaId, Bundle extras) {
- mControllerStub.playFromMediaId(packageName, caller, mediaId, extras);
- }
-
- @Override
- public void playFromSearch(String packageName, ControllerCallbackLink caller,
- String query, Bundle extras) {
- mControllerStub.playFromSearch(packageName, caller, query, extras);
- }
-
- @Override
- public void playFromUri(String packageName, ControllerCallbackLink caller,
- Uri uri, Bundle extras) {
- mControllerStub.playFromUri(packageName, caller, uri, extras);
- }
-
- @Override
- public void skipToQueueItem(String packageName, ControllerCallbackLink caller, long id) {
- mControllerStub.skipToQueueItem(packageName, caller, id);
- }
-
- @Override
- public void pause(String packageName, ControllerCallbackLink caller) {
- mControllerStub.pause(packageName, caller);
- }
-
- @Override
- public void stop(String packageName, ControllerCallbackLink caller) {
- mControllerStub.stop(packageName, caller);
- }
-
- @Override
- public void next(String packageName, ControllerCallbackLink caller) {
- mControllerStub.next(packageName, caller);
- }
-
- @Override
- public void previous(String packageName, ControllerCallbackLink caller) {
- mControllerStub.previous(packageName, caller);
- }
-
- @Override
- public void fastForward(String packageName, ControllerCallbackLink caller) {
- mControllerStub.fastForward(packageName, caller);
- }
-
- @Override
- public void rewind(String packageName, ControllerCallbackLink caller) {
- mControllerStub.rewind(packageName, caller);
- }
-
- @Override
- public void seekTo(String packageName, ControllerCallbackLink caller, long pos) {
- mControllerStub.seekTo(packageName, caller, pos);
- }
-
- @Override
- public void rate(String packageName, ControllerCallbackLink caller, Rating rating) {
- mControllerStub.rate(packageName, caller, rating);
- }
-
- @Override
- public void setPlaybackSpeed(String packageName, ControllerCallbackLink caller,
- float speed) {
- mControllerStub.setPlaybackSpeed(packageName, caller, speed);
- }
-
- @Override
- public void sendCustomAction(String packageName, ControllerCallbackLink caller,
- String action, Bundle args) {
- mControllerStub.sendCustomAction(packageName, caller, action, args);
- }
-
- @Override
- public MediaMetadata getMetadata() {
- return mControllerStub.getMetadata();
- }
-
- @Override
- public PlaybackState getPlaybackState() {
- return mControllerStub.getPlaybackState();
- }
-
- @Override
- public MediaParceledListSlice getQueue() {
- List<MediaSession.QueueItem> queue = mControllerStub.getQueue();
- return queue == null ? null : new MediaParceledListSlice(queue);
- }
-
- @Override
- public CharSequence getQueueTitle() {
- return mControllerStub.getQueueTitle();
- }
-
- @Override
- public Bundle getExtras() {
- return mControllerStub.getExtras();
- }
-
- @Override
- public int getRatingType() {
- return mControllerStub.getRatingType();
- }
- }
-}
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 9b1ad7b..fcde95a 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -19,7 +19,7 @@
import android.media.AudioAttributes;
import android.media.MediaMetadata;
import android.media.MediaParceledListSlice;
-import android.media.session.ControllerLink;
+import android.media.session.ISessionController;
import android.media.session.PlaybackState;
import android.media.session.MediaSession;
import android.os.Bundle;
@@ -31,7 +31,7 @@
*/
interface ISession {
void sendEvent(String event, in Bundle data);
- ControllerLink getController();
+ ISessionController getController();
void setFlags(int flags);
void setActive(boolean active);
void setMediaButtonReceiver(in PendingIntent mbr);
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index cfcc294..02348476 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -22,10 +22,10 @@
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
import android.media.session.ISession2TokensListener;
import android.media.session.MediaSession;
import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
import android.os.Bundle;
import android.view.KeyEvent;
@@ -34,7 +34,7 @@
* @hide
*/
interface ISessionManager {
- SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
+ ISession createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
in Bundle sessionInfo, int userId);
void notifySession2Created(in Session2Token sessionToken);
List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 7334044..036cd78 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -24,6 +24,7 @@
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.session.MediaSession.QueueItem;
@@ -34,6 +35,7 @@
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.text.TextUtils;
import android.util.Log;
@@ -67,7 +69,7 @@
private static final int MSG_UPDATE_EXTRAS = 7;
private static final int MSG_DESTROYED = 8;
- private final ControllerLink mSessionBinder;
+ private final ISessionController mSessionBinder;
private final MediaSession.Token mToken;
private final Context mContext;
@@ -95,10 +97,10 @@
if (token == null) {
throw new IllegalArgumentException("token shouldn't be null");
}
- if (token.getControllerLink() == null) {
- throw new IllegalArgumentException("token.getControllerLink() shouldn't be null");
+ if (token.getBinder() == null) {
+ throw new IllegalArgumentException("token.getBinder() shouldn't be null");
}
- mSessionBinder = token.getControllerLink();
+ mSessionBinder = token.getBinder();
mTransportControls = new TransportControls();
mToken = token;
mContext = context;
@@ -131,7 +133,7 @@
}
try {
return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub, keyEvent);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
// System is dead. =(
}
return false;
@@ -145,7 +147,7 @@
public @Nullable PlaybackState getPlaybackState() {
try {
return mSessionBinder.getPlaybackState();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getPlaybackState.", e);
return null;
}
@@ -159,7 +161,7 @@
public @Nullable MediaMetadata getMetadata() {
try {
return mSessionBinder.getMetadata();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getMetadata.", e);
return null;
}
@@ -173,8 +175,9 @@
*/
public @Nullable List<MediaSession.QueueItem> getQueue() {
try {
- return mSessionBinder.getQueue();
- } catch (RuntimeException e) {
+ MediaParceledListSlice list = mSessionBinder.getQueue();
+ return list == null ? null : list.getList();
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getQueue.", e);
}
return null;
@@ -186,7 +189,7 @@
public @Nullable CharSequence getQueueTitle() {
try {
return mSessionBinder.getQueueTitle();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getQueueTitle", e);
}
return null;
@@ -198,7 +201,7 @@
public @Nullable Bundle getExtras() {
try {
return mSessionBinder.getExtras();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getExtras", e);
}
return null;
@@ -221,7 +224,7 @@
public int getRatingType() {
try {
return mSessionBinder.getRatingType();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getRatingType.", e);
return Rating.RATING_NONE;
}
@@ -235,7 +238,7 @@
public long getFlags() {
try {
return mSessionBinder.getFlags();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getFlags.", e);
}
return 0;
@@ -249,7 +252,7 @@
public @Nullable PlaybackInfo getPlaybackInfo() {
try {
return mSessionBinder.getVolumeAttributes();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getAudioInfo.", e);
}
return null;
@@ -264,7 +267,7 @@
public @Nullable PendingIntent getSessionActivity() {
try {
return mSessionBinder.getLaunchPendingIntent();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling getPendingIntent.", e);
}
return null;
@@ -297,7 +300,7 @@
// AppOpsManager usages.
mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
mCbStub, value, flags);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling setVolumeTo.", e);
}
}
@@ -322,7 +325,7 @@
// AppOpsManager usages.
mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
mCbStub, direction, flags);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
}
}
@@ -388,7 +391,7 @@
}
try {
mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.d(TAG, "Dead object in sendCommand.", e);
}
}
@@ -402,7 +405,7 @@
if (mPackageName == null) {
try {
mPackageName = mSessionBinder.getPackageName();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.d(TAG, "Dead object in getPackageName.", e);
}
}
@@ -419,7 +422,7 @@
if (mSessionInfo == null) {
try {
mSessionInfo = mSessionBinder.getSessionInfo();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.d(TAG, "Dead object in getSessionInfo.", e);
}
}
@@ -436,7 +439,7 @@
if (mTag == null) {
try {
mTag = mSessionBinder.getTag();
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.d(TAG, "Dead object in getTag.", e);
}
}
@@ -446,7 +449,7 @@
/*
* @hide
*/
- ControllerLink getSessionBinder() {
+ ISessionController getSessionBinder() {
return mSessionBinder;
}
@@ -456,7 +459,7 @@
@UnsupportedAppUsage
public boolean controlsSameSession(MediaController other) {
if (other == null) return false;
- return mSessionBinder.getBinder() == other.getSessionBinder().getBinder();
+ return mSessionBinder.asBinder() == other.getSessionBinder().asBinder();
}
private void addCallbackLocked(Callback cb, Handler handler) {
@@ -472,7 +475,7 @@
try {
mSessionBinder.registerCallback(mContext.getPackageName(), mCbStub);
mCbRegistered = true;
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.e(TAG, "Dead object in registerCallback", e);
}
}
@@ -491,7 +494,7 @@
if (mCbRegistered && mCallbacks.size() == 0) {
try {
mSessionBinder.unregisterCallback(mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.e(TAG, "Dead object in removeCallbackLocked");
}
mCbRegistered = false;
@@ -618,7 +621,7 @@
public void prepare() {
try {
mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare.", e);
}
}
@@ -643,7 +646,7 @@
try {
mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
extras);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
}
}
@@ -670,7 +673,7 @@
try {
mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
extras);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
}
}
@@ -694,7 +697,7 @@
}
try {
mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
}
}
@@ -705,7 +708,7 @@
public void play() {
try {
mSessionBinder.play(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling play.", e);
}
}
@@ -725,7 +728,7 @@
try {
mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
extras);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
}
}
@@ -747,7 +750,7 @@
}
try {
mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + query + ").", e);
}
}
@@ -766,7 +769,7 @@
}
try {
mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling play(" + uri + ").", e);
}
}
@@ -778,7 +781,7 @@
public void skipToQueueItem(long id) {
try {
mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
}
}
@@ -790,7 +793,7 @@
public void pause() {
try {
mSessionBinder.pause(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling pause.", e);
}
}
@@ -802,7 +805,7 @@
public void stop() {
try {
mSessionBinder.stop(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling stop.", e);
}
}
@@ -815,7 +818,7 @@
public void seekTo(long pos) {
try {
mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling seekTo.", e);
}
}
@@ -827,7 +830,7 @@
public void fastForward() {
try {
mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling fastForward.", e);
}
}
@@ -838,7 +841,7 @@
public void skipToNext() {
try {
mSessionBinder.next(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling next.", e);
}
}
@@ -850,7 +853,7 @@
public void rewind() {
try {
mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling rewind.", e);
}
}
@@ -861,7 +864,7 @@
public void skipToPrevious() {
try {
mSessionBinder.previous(mContext.getPackageName(), mCbStub);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling previous.", e);
}
}
@@ -876,7 +879,7 @@
public void setRating(Rating rating) {
try {
mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling rate.", e);
}
}
@@ -889,7 +892,7 @@
public void setPlaybackSpeed(float speed) {
try {
mSessionBinder.setPlaybackSpeed(mContext.getPackageName(), mCbStub, speed);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error calling setPlaybackSpeed.", e);
}
}
@@ -924,7 +927,7 @@
}
try {
mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.d(TAG, "Dead object in sendCustomAction.", e);
}
}
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index c4f8b79..cbc6c9d 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -36,6 +36,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.media.MediaBrowserService;
import android.text.TextUtils;
@@ -163,11 +164,11 @@
.getSystemService(Context.MEDIA_SESSION_SERVICE);
try {
SessionCallbackLink cbLink = new SessionCallbackLink(context);
- SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo);
- mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
+ ISession binder = manager.createSession(cbLink, tag, sessionInfo);
+ mImpl = new MediaSessionEngine(context, binder, cbLink);
mMaxBitmapSize = context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
throw new RuntimeException("Remote error creating session.", e);
}
}
@@ -445,19 +446,19 @@
public static final class Token implements Parcelable {
private final int mUid;
- private final ControllerLink mControllerLink;
+ private final ISessionController mBinder;
/**
* @hide
*/
- public Token(ControllerLink controllerLink) {
+ public Token(ISessionController binder) {
mUid = Process.myUid();
- mControllerLink = controllerLink;
+ mBinder = binder;
}
Token(Parcel in) {
mUid = in.readInt();
- mControllerLink = in.readParcelable(null);
+ mBinder = ISessionController.Stub.asInterface(in.readStrongBinder());
}
@Override
@@ -468,15 +469,14 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mUid);
- dest.writeParcelable(mControllerLink, flags);
+ dest.writeStrongBinder(mBinder.asBinder());
}
@Override
public int hashCode() {
final int prime = 31;
int result = mUid;
- result = prime * result + ((mControllerLink == null)
- ? 0 : mControllerLink.getBinder().hashCode());
+ result = prime * result + (mBinder == null ? 0 : mBinder.asBinder().hashCode());
return result;
}
@@ -492,7 +492,10 @@
if (mUid != other.mUid) {
return false;
}
- return Objects.equals(mControllerLink, other.mControllerLink);
+ if (mBinder == null || other.mBinder == null) {
+ return mBinder == other.mBinder;
+ }
+ return Objects.equals(mBinder.asBinder(), other.mBinder.asBinder());
}
/**
@@ -504,11 +507,11 @@
}
/**
- * Gets the controller link in this token.
+ * Gets the controller binder in this token.
* @hide
*/
- public ControllerLink getControllerLink() {
- return mControllerLink;
+ public ISessionController getBinder() {
+ return mBinder;
}
public static final @android.annotation.NonNull Parcelable.Creator<Token> CREATOR =
diff --git a/media/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java
index 266bf32..7c5243a 100644
--- a/media/java/android/media/session/MediaSessionEngine.java
+++ b/media/java/android/media/session/MediaSessionEngine.java
@@ -25,6 +25,7 @@
import android.media.AudioAttributes;
import android.media.MediaDescription;
import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.session.MediaSessionManager.RemoteUserInfo;
@@ -34,6 +35,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.media.MediaBrowserService;
import android.text.TextUtils;
@@ -55,7 +57,7 @@
private final MediaSession.Token mSessionToken;
private final MediaController mController;
- private final SessionLink mSessionLink;
+ private final ISession mBinder;
private CallbackMessageHandler mCallbackHandler;
private VolumeProvider mVolumeProvider;
@@ -70,14 +72,14 @@
* finished with the session.
*
* @param context The context to use to create the session.
- * @param sessionLink A session link for the binder of MediaSessionRecord
+ * @param binder A session binder
*/
- public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink,
- @NonNull SessionCallbackLink cbLink) {
- mSessionLink = sessionLink;
+ public MediaSessionEngine(@NonNull Context context, @NonNull ISession binder,
+ @NonNull SessionCallbackLink cbLink) throws RemoteException {
+ mBinder = binder;
cbLink.setSessionEngine(this);
- mSessionToken = new MediaSession.Token(mSessionLink.getController());
+ mSessionToken = new MediaSession.Token(mBinder.getController());
mController = new MediaController(context, mSessionToken);
}
@@ -134,8 +136,8 @@
*/
public void setSessionActivity(@Nullable PendingIntent pi) {
try {
- mSessionLink.setLaunchPendingIntent(pi);
- } catch (RuntimeException e) {
+ mBinder.setLaunchPendingIntent(pi);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
}
}
@@ -150,8 +152,8 @@
*/
public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
try {
- mSessionLink.setMediaButtonReceiver(mbr);
- } catch (RuntimeException e) {
+ mBinder.setMediaButtonReceiver(mbr);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
}
}
@@ -163,8 +165,8 @@
*/
public void setFlags(int flags) {
try {
- mSessionLink.setFlags(flags);
- } catch (RuntimeException e) {
+ mBinder.setFlags(flags);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setFlags.", e);
}
}
@@ -185,8 +187,8 @@
throw new IllegalArgumentException("Attributes cannot be null for local playback.");
}
try {
- mSessionLink.setPlaybackToLocal(attributes);
- } catch (RuntimeException e) {
+ mBinder.setPlaybackToLocal(attributes);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
}
}
@@ -217,10 +219,10 @@
});
try {
- mSessionLink.setPlaybackToRemote(volumeProvider.getVolumeControl(),
+ mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
volumeProvider.getMaxVolume());
- mSessionLink.setCurrentVolume(volumeProvider.getCurrentVolume());
- } catch (RuntimeException e) {
+ mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
}
}
@@ -238,9 +240,9 @@
return;
}
try {
- mSessionLink.setActive(active);
+ mBinder.setActive(active);
mActive = active;
- } catch (RuntimeException e) {
+ } catch (RemoteException e) {
Log.wtf(TAG, "Failure in setActive.", e);
}
}
@@ -267,8 +269,8 @@
throw new IllegalArgumentException("event cannot be null or empty");
}
try {
- mSessionLink.sendEvent(event, extras);
- } catch (RuntimeException e) {
+ mBinder.sendEvent(event, extras);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error sending event", e);
}
}
@@ -280,8 +282,8 @@
*/
public void close() {
try {
- mSessionLink.destroySession();
- } catch (RuntimeException e) {
+ mBinder.destroySession();
+ } catch (RemoteException e) {
Log.wtf(TAG, "Error releasing session: ", e);
}
}
@@ -316,8 +318,8 @@
public void setPlaybackState(@Nullable PlaybackState state) {
mPlaybackState = state;
try {
- mSessionLink.setPlaybackState(state);
- } catch (RuntimeException e) {
+ mBinder.setPlaybackState(state);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Dead object in setPlaybackState.", e);
}
}
@@ -344,8 +346,8 @@
String metadataDescription = "size=" + fields + ", description=" + description;
try {
- mSessionLink.setMetadata(metadata, duration, metadataDescription);
- } catch (RuntimeException e) {
+ mBinder.setMetadata(metadata, duration, metadataDescription);
+ } catch (RemoteException e) {
Log.wtf(TAG, "Dead object in setPlaybackState.", e);
}
}
@@ -363,8 +365,8 @@
*/
public void setQueue(@Nullable List<MediaSession.QueueItem> queue) {
try {
- mSessionLink.setQueue(queue);
- } catch (RuntimeException e) {
+ mBinder.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
+ } catch (RemoteException e) {
Log.wtf("Dead object in setQueue.", e);
}
}
@@ -378,8 +380,8 @@
*/
public void setQueueTitle(@Nullable CharSequence title) {
try {
- mSessionLink.setQueueTitle(title);
- } catch (RuntimeException e) {
+ mBinder.setQueueTitle(title);
+ } catch (RemoteException e) {
Log.wtf("Dead object in setQueueTitle.", e);
}
}
@@ -399,8 +401,8 @@
*/
public void setRatingType(int type) {
try {
- mSessionLink.setRatingType(type);
- } catch (RuntimeException e) {
+ mBinder.setRatingType(type);
+ } catch (RemoteException e) {
Log.e(TAG, "Error in setRatingType.", e);
}
}
@@ -414,8 +416,8 @@
*/
public void setExtras(@Nullable Bundle extras) {
try {
- mSessionLink.setExtras(extras);
- } catch (RuntimeException e) {
+ mBinder.setExtras(extras);
+ } catch (RemoteException e) {
Log.wtf("Dead object in setExtras.", e);
}
}
@@ -464,8 +466,8 @@
}
}
try {
- mSessionLink.setCurrentVolume(provider.getCurrentVolume());
- } catch (RuntimeException e) {
+ mBinder.setCurrentVolume(provider.getCurrentVolume());
+ } catch (RemoteException e) {
Log.e(TAG, "Error in notifyVolumeChanged", e);
}
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index f530442..7ca5c93 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -107,7 +107,7 @@
* @hide
*/
@NonNull
- public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
+ public ISession createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
@Nullable Bundle sessionInfo) {
try {
return mService.createSession(mContext.getPackageName(), cbStub, tag, sessionInfo,
diff --git a/media/java/android/media/session/SessionLink.aidl b/media/java/android/media/session/SessionLink.aidl
deleted file mode 100644
index c3be23e..0000000
--- a/media/java/android/media/session/SessionLink.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 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 android.media.session;
-
-parcelable SessionLink;
diff --git a/media/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java
deleted file mode 100644
index 2b42a2d6..0000000
--- a/media/java/android/media/session/SessionLink.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright 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 android.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession.QueueItem;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-import java.util.List;
-
-/**
- * Handles incoming commands from {@link MediaSession}.
- * @hide
- */
-public final class SessionLink implements Parcelable {
- public static final @android.annotation.NonNull Parcelable.Creator<SessionLink> CREATOR =
- new Parcelable.Creator<SessionLink>() {
- @Override
- public SessionLink createFromParcel(Parcel in) {
- return new SessionLink(in.readStrongBinder());
- }
-
- @Override
- public SessionLink[] newArray(int size) {
- return new SessionLink[size];
- }
- };
-
- final SessionStub mSessionStub;
- final ISession mISession;
-
- /**
- * Constructor for stub (Callee)
- */
- public SessionLink(@NonNull SessionStub sessionStub) {
- mSessionStub = sessionStub;
- mISession = new StubProxy();
- }
-
- /**
- * Constructor for interface (Caller)
- */
- public SessionLink(IBinder binder) {
- mSessionStub = null;
- mISession = ISession.Stub.asInterface(binder);
- }
-
- /**
- * Tell system that the session sends an event to all the connected controllers.
- *
- * @param event the name of the event
- * @param extras the extras included with the event
- */
- void sendEvent(@NonNull String event, @Nullable Bundle extras) {
- try {
- mISession.sendEvent(event, extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Gets the controller link from the system.
- */
- @NonNull
- ControllerLink getController() {
- try {
- return mISession.getController();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the flags.
- *
- * @param flags the new session flags
- */
- void setFlags(int flags) {
- try {
- mISession.setFlags(flags);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session is (in)active.
- *
- * @param active the new activeness state
- */
- void setActive(boolean active) {
- try {
- mISession.setActive(active);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the media button receiver.
- *
- * @param mbr the pending intent for media button receiver
- */
- void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
- try {
- mISession.setMediaButtonReceiver(mbr);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the pending intent for launching UI.
- *
- * @param pi the pending intent for launching UI
- */
- void setLaunchPendingIntent(@Nullable PendingIntent pi) {
- try {
- mISession.setLaunchPendingIntent(pi);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session is destroyed.
- */
- void destroySession() {
- try {
- mISession.destroySession();
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new metadata.
- *
- * @param metadata the new metadata
- * @param duration the duration of the media in milliseconds
- * @param metadataDescription the description of the metadata
- */
- void setMetadata(@Nullable MediaMetadata metadata, long duration,
- @Nullable String metadataDescription) {
- try {
- mISession.setMetadata(metadata, duration, metadataDescription);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new playback state.
- *
- * @param state the new playback state
- */
- void setPlaybackState(@Nullable PlaybackState state) {
- try {
- mISession.setPlaybackState(state);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new queue.
- *
- * @param queue the new queue
- */
- void setQueue(@Nullable List<QueueItem> queue) {
- try {
- mISession.setQueue(queue == null ? null : new MediaParceledListSlice(queue));
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new queue title.
- *
- * @param title the new queue title
- */
- void setQueueTitle(@Nullable CharSequence title) {
- try {
- mISession.setQueueTitle(title);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new extras.
- *
- * @param extras the new extras
- */
- void setExtras(@Nullable Bundle extras) {
- try {
- mISession.setExtras(extras);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new rating type of the current media.
- *
- * @param type the rating type.
- */
- void setRatingType(int type) {
- try {
- mISession.setRatingType(type);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session represents a local playback.
- *
- * @param attributes the audio attributes of the local playback.
- */
- void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
- try {
- mISession.setPlaybackToLocal(attributes);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session represents a remote playback.
- *
- * @param control the volume control type
- * @param max the max volume
- */
- void setPlaybackToRemote(int control, int max) {
- try {
- mISession.setPlaybackToRemote(control, max);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Tell system that the session sets the new current volume.
- *
- * @param currentVolume the new current volume
- */
- void setCurrentVolume(int currentVolume) {
- try {
- mISession.setCurrentVolume(currentVolume);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- }
-
- /** Gets the binder */
- @NonNull
- public IBinder getBinder() {
- return mISession.asBinder();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mISession.asBinder());
- }
-
- /**
- * Class for Stub implementation
- */
- public abstract static class SessionStub {
- /** Stub method for ISession.sendEvent */
- public void sendEvent(@NonNull String event, @Nullable Bundle data) {
- }
-
- /** Stub method for ISession.getController */
- @NonNull
- public ControllerLink getController() {
- return null;
- }
-
- /** Stub method for ISession.setFlags */
- public void setFlags(int flags) {
- }
-
- /** Stub method for ISession.setActive */
- public void setActive(boolean active) {
- }
-
- /** Stub method for ISession.setMediaButtonReceiver */
- public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
- }
-
- /** Stub method for ISession.setLaunchPendingIntent */
- public void setLaunchPendingIntent(@Nullable PendingIntent pi) {
- }
-
- /** Stub method for ISession.destroySession */
- public void destroySession() {
- }
-
- /** Stub method for ISession.setMetadata */
- public void setMetadata(@Nullable MediaMetadata metadata, long duration,
- @Nullable String metadataDescription) {
- }
-
- /** Stub method for ISession.setPlaybackState */
- public void setPlaybackState(@Nullable PlaybackState state) {
- }
-
- /** Stub method for ISession.setQueue */
- public void setQueue(@Nullable List<QueueItem> queue) {
- }
-
- /** Stub method for ISession.setQueueTitle */
- public void setQueueTitle(@Nullable CharSequence title) {
- }
-
- /** Stub method for ISession.setExtras */
- public void setExtras(@Nullable Bundle extras) {
- }
-
- /** Stub method for ISession.setRatingType */
- public void setRatingType(int type) {
- }
-
- /** Stub method for ISession.setPlaybackToLocal */
- public void setPlaybackToLocal(@NonNull AudioAttributes attributes) {
- }
-
- /** Stub method for ISession.setPlaybackToRemote */
- public void setPlaybackToRemote(int control, int max) {
- }
-
- /** Stub method for ISession.setCurrentVolume */
- public void setCurrentVolume(int currentVolume) {
- }
- }
-
- private class StubProxy extends ISession.Stub {
- @Override
- public void sendEvent(String event, Bundle data) {
- mSessionStub.sendEvent(event, data);
- }
-
- @Override
- public ControllerLink getController() {
- return mSessionStub.getController();
- }
-
- @Override
- public void setFlags(int flags) {
- mSessionStub.setFlags(flags);
- }
-
- @Override
- public void setActive(boolean active) {
- mSessionStub.setActive(active);
- }
-
- @Override
- public void setMediaButtonReceiver(PendingIntent mbr) {
- mSessionStub.setMediaButtonReceiver(mbr);
- }
-
- @Override
- public void setLaunchPendingIntent(PendingIntent pi) {
- mSessionStub.setLaunchPendingIntent(pi);
- }
-
- @Override
- public void destroySession() {
- mSessionStub.destroySession();
- }
-
- @Override
- public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
- mSessionStub.setMetadata(metadata, duration, metadataDescription);
- }
-
- @Override
- public void setPlaybackState(PlaybackState state) {
- mSessionStub.setPlaybackState(state);
- }
-
- @Override
- public void setQueue(MediaParceledListSlice queue) {
- mSessionStub.setQueue(queue == null ? null : queue.getList());
- }
-
- @Override
- public void setQueueTitle(CharSequence title) {
- mSessionStub.setQueueTitle(title);
- }
-
- @Override
- public void setExtras(Bundle extras) {
- mSessionStub.setExtras(extras);
- }
-
- @Override
- public void setRatingType(int type) {
- mSessionStub.setRatingType(type);
- }
-
- @Override
- public void setPlaybackToLocal(AudioAttributes attributes) {
- mSessionStub.setPlaybackToLocal(attributes);
- }
-
- @Override
- public void setPlaybackToRemote(int control, int max) {
- mSessionStub.setPlaybackToRemote(control, max);
- }
-
- @Override
- public void setCurrentVolume(int currentVolume) {
- mSessionStub.setCurrentVolume(currentVolume);
- }
- }
-}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 474b671..dc2d177 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -54,6 +54,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.IntStream;
@@ -248,7 +249,7 @@
public MtpDatabase(Context context, String volumeName,
String[] subDirectories) {
native_setup();
- mContext = context;
+ mContext = Objects.requireNonNull(context);
mMediaProvider = context.getContentResolver()
.acquireContentProviderClient(MediaStore.AUTHORITY);
mVolumeName = volumeName;
@@ -294,6 +295,10 @@
}
}
+ public Context getContext() {
+ return mContext;
+ }
+
@Override
public void close() {
mManager.close();
diff --git a/media/java/android/mtp/MtpServer.java b/media/java/android/mtp/MtpServer.java
index a555d37..f0ab9a3 100644
--- a/media/java/android/mtp/MtpServer.java
+++ b/media/java/android/mtp/MtpServer.java
@@ -18,7 +18,12 @@
import com.android.internal.util.Preconditions;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.ByteStringUtils;
+
import java.io.FileDescriptor;
+import java.util.Random;
/**
* Java wrapper for MTP/PTP support as USB responder.
@@ -29,6 +34,12 @@
private long mNativeContext; // accessed by native methods
private final MtpDatabase mDatabase;
private final Runnable mOnTerminate;
+ private final Context mContext;
+
+// It requires "exactly 32 characters, including any leading 0s" in MTP spec
+// (5.1.1.14 Serial Number)
+ private static final int sID_LEN_BYTES = 16;
+ private static final int sID_LEN_STR = (sID_LEN_BYTES * 2);
static {
System.loadLibrary("media_jni");
@@ -41,10 +52,41 @@
Runnable onTerminate,
String deviceInfoManufacturer,
String deviceInfoModel,
- String deviceInfoDeviceVersion,
- String deviceInfoSerialNumber) {
+ String deviceInfoDeviceVersion) {
mDatabase = Preconditions.checkNotNull(database);
mOnTerminate = Preconditions.checkNotNull(onTerminate);
+ mContext = mDatabase.getContext();
+
+ final String strID_PREFS_NAME = "mtp-cfg";
+ final String strID_PREFS_KEY = "mtp-id";
+ String strRandomId = null;
+ String deviceInfoSerialNumber;
+
+ SharedPreferences sharedPref =
+ mContext.getSharedPreferences(strID_PREFS_NAME, Context.MODE_PRIVATE);
+ if (sharedPref.contains(strID_PREFS_KEY)) {
+ strRandomId = sharedPref.getString(strID_PREFS_KEY, null);
+
+ // Check for format consistence (regenerate upon corruption)
+ if (strRandomId.length() != sID_LEN_STR) {
+ strRandomId = null;
+ } else {
+ // Only accept hex digit
+ for (int ii = 0; ii < strRandomId.length(); ii++)
+ if (Character.digit(strRandomId.charAt(ii), 16) == -1) {
+ strRandomId = null;
+ break;
+ }
+ }
+ }
+
+ if (strRandomId == null) {
+ strRandomId = getRandId();
+ sharedPref.edit().putString(strID_PREFS_KEY, strRandomId).apply();
+ }
+
+ deviceInfoSerialNumber = strRandomId;
+
native_setup(
database,
controlFd,
@@ -56,6 +98,14 @@
database.setServer(this);
}
+ private String getRandId() {
+ Random randomVal = new Random();
+ byte[] randomBytes = new byte[sID_LEN_BYTES];
+
+ randomVal.nextBytes(randomBytes);
+ return ByteStringUtils.toHexString(randomBytes);
+ }
+
public void start() {
Thread thread = new Thread(this, "MtpServer");
thread.start();
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 365e045..d28c15c 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -109,7 +109,8 @@
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
CHECK(gFields.context != NULL);
- gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
+ gFields.readAtMethodID = env->GetMethodID(
+ clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I");
}
static void android_media_MediaHTTPConnection_native_setup(
@@ -132,7 +133,7 @@
}
static jint android_media_MediaHTTPConnection_native_readAt(
- JNIEnv *env, jobject thiz, jlong offset, jint size) {
+ JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) {
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
if (size > JMediaHTTPConnection::kBufferSize) {
size = JMediaHTTPConnection::kBufferSize;
@@ -141,7 +142,7 @@
jbyteArray byteArrayObj = conn->getByteArrayObj();
jint n = env->CallIntMethod(
- thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
+ thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState);
if (n > 0) {
env->GetByteArrayRegion(
@@ -158,7 +159,7 @@
{ "native_getIMemory", "()Landroid/os/IBinder;",
(void *)android_media_MediaHTTPConnection_native_getIMemory },
- { "native_readAt", "(JI)I",
+ { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I",
(void *)android_media_MediaHTTPConnection_native_readAt },
{ "native_init", "()V",
diff --git a/media/mca/Android.mk b/media/mca/Android.mk
deleted file mode 100644
index b1ce91e..0000000
--- a/media/mca/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2011 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.
-#
-
-#
-# Build all native libraries
-#
-include $(call all-subdir-makefiles)
-
-
diff --git a/media/mca/samples/Android.mk b/media/mca/samples/Android.mk
deleted file mode 100644
index b1ce91e..0000000
--- a/media/mca/samples/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (C) 2011 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.
-#
-
-#
-# Build all native libraries
-#
-include $(call all-subdir-makefiles)
-
-
diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.bp b/media/mca/samples/CameraEffectsRecordingSample/Android.bp
new file mode 100644
index 0000000..96e81ab
--- /dev/null
+++ b/media/mca/samples/CameraEffectsRecordingSample/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2011 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.
+//
+
+// Build activity
+
+android_test {
+ name: "CameraEffectsRecordingSample",
+ srcs: ["**/*.java"],
+ platform_apis: true,
+ optimize: {
+ enabled: false,
+ },
+}
+
diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.mk b/media/mca/samples/CameraEffectsRecordingSample/Android.mk
deleted file mode 100644
index c81f2fc..0000000
--- a/media/mca/samples/CameraEffectsRecordingSample/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2011 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.
-#
-
-# Build activity
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := CameraEffectsRecordingSample
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-# ============================================================
-
-# Also build all of the sub-targets under this one: the shared library.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/mca/tests/Android.bp b/media/mca/tests/Android.bp
new file mode 100644
index 0000000..6b11dd9
--- /dev/null
+++ b/media/mca/tests/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+ name: "CameraEffectsTests",
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ instrumentation_for: "CameraEffectsRecordingSample",
+}
diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk
deleted file mode 100644
index 648af4e..0000000
--- a/media/mca/tests/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CameraEffectsTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_INSTRUMENTATION_FOR := CameraEffectsRecordingSample
-
-include $(BUILD_PACKAGE)
-
-
diff --git a/media/packages/BluetoothMidiService/Android.bp b/media/packages/BluetoothMidiService/Android.bp
new file mode 100644
index 0000000..f45114a
--- /dev/null
+++ b/media/packages/BluetoothMidiService/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+ name: "BluetoothMidiService",
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/media/packages/BluetoothMidiService/Android.mk b/media/packages/BluetoothMidiService/Android.mk
deleted file mode 100644
index 6f262bf..0000000
--- a/media/packages/BluetoothMidiService/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES += \
- $(call all-java-files-under,src)
-
-LOCAL_PACKAGE_NAME := BluetoothMidiService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/CameraBrowser/Android.bp b/media/tests/CameraBrowser/Android.bp
new file mode 100644
index 0000000..8e3ca19
--- /dev/null
+++ b/media/tests/CameraBrowser/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+ name: "CameraBrowser",
+ srcs: ["**/*.java"],
+ sdk_version: "current",
+}
diff --git a/media/tests/CameraBrowser/Android.mk b/media/tests/CameraBrowser/Android.mk
deleted file mode 100644
index 46596a7..0000000
--- a/media/tests/CameraBrowser/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := CameraBrowser
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/EffectsTest/Android.bp b/media/tests/EffectsTest/Android.bp
new file mode 100644
index 0000000..214e8c0
--- /dev/null
+++ b/media/tests/EffectsTest/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+ name: "EffectsTest",
+ srcs: ["**/*.java"],
+ platform_apis: true,
+}
diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk
deleted file mode 100644
index a066950..0000000
--- a/media/tests/EffectsTest/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := EffectsTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/MediaDump/Android.bp b/media/tests/MediaDump/Android.bp
new file mode 100644
index 0000000..0eba8b2
--- /dev/null
+++ b/media/tests/MediaDump/Android.bp
@@ -0,0 +1,6 @@
+android_app {
+ name: "MediaDump",
+ // Only compile source java files in this apk.
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/media/tests/MediaDump/Android.mk b/media/tests/MediaDump/Android.mk
deleted file mode 100644
index 74afdd0..0000000
--- a/media/tests/MediaDump/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-# Only compile source java files in this apk.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := MediaDump
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
-
-# Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/tests/ScoAudioTest/Android.bp b/media/tests/ScoAudioTest/Android.bp
new file mode 100644
index 0000000..ad2b9171
--- /dev/null
+++ b/media/tests/ScoAudioTest/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+ name: "scoaudiotest",
+ platform_apis: true,
+ srcs: ["**/*.java"],
+}
diff --git a/media/tests/ScoAudioTest/Android.mk b/media/tests/ScoAudioTest/Android.mk
deleted file mode 100644
index 2ad91a4..0000000
--- a/media/tests/ScoAudioTest/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-#LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := scoaudiotest
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/SoundPoolTest/Android.bp b/media/tests/SoundPoolTest/Android.bp
new file mode 100644
index 0000000..473f531
--- /dev/null
+++ b/media/tests/SoundPoolTest/Android.bp
@@ -0,0 +1,5 @@
+android_test {
+ name: "SoundPoolTest",
+ srcs: ["**/*.java"],
+ platform_apis: true,
+}
diff --git a/media/tests/SoundPoolTest/Android.mk b/media/tests/SoundPoolTest/Android.mk
deleted file mode 100644
index 9ca33c8..0000000
--- a/media/tests/SoundPoolTest/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := SoundPoolTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/players/Android.bp b/media/tests/players/Android.bp
new file mode 100644
index 0000000..23c5f04
--- /dev/null
+++ b/media/tests/players/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2009 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.
+
+cc_test_library {
+ name: "invoke_mock_media_player",
+ srcs: ["invoke_mock_media_player.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libmedia",
+ "libutils",
+ "liblog",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ gtest: false,
+}
diff --git a/media/tests/players/Android.mk b/media/tests/players/Android.mk
deleted file mode 100644
index ee9d850..0000000
--- a/media/tests/players/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= invoke_mock_media_player.cpp
-
-LOCAL_SHARED_LIBRARIES:= \
- libbinder \
- libmedia \
- libutils \
- liblog
-
-LOCAL_MODULE:= invoke_mock_media_player
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index a288d010..bda5743 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -52,6 +52,7 @@
import android.webkit.CookieManager;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
+import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -409,8 +410,7 @@
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1,
getResources().getDisplayMetrics());
private int mPagesLoaded;
- // the host of the page that this webview is currently loading. Can be null when undefined.
- private String mHostname;
+ private String mMainFrameUrl;
// If we haven't finished cleaning up the history, don't allow going back.
public boolean allowBack() {
@@ -436,7 +436,6 @@
}
final URL url = makeURL(urlString);
Log.d(TAG, "onPageStarted: " + sanitizeURL(url));
- mHostname = host(url);
// For internally generated pages, leave URL bar listing prior URL as this is the URL
// the page refers to.
if (!urlString.startsWith(INTERNAL_ASSETS)) {
@@ -480,17 +479,28 @@
return Integer.toString((int)dp) + "px";
}
+ // Check if webview is trying to load the main frame and record its url.
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ if (request.isForMainFrame()) {
+ mMainFrameUrl = request.getUrl().toString();
+ }
+ return false;
+ }
+
// A web page consisting of a large broken lock icon to indicate SSL failure.
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
- final URL url = makeURL(error.getUrl());
- final String host = host(url);
+ final URL errorUrl = makeURL(error.getUrl());
+ final URL mainFrameUrl = makeURL(mMainFrameUrl);
Log.d(TAG, String.format("SSL error: %s, url: %s, certificate: %s",
- sslErrorName(error), sanitizeURL(url), error.getCertificate()));
- if (url == null || !Objects.equals(host, mHostname)) {
- // Ignore ssl errors for resources coming from a different hostname than the page
- // that we are currently loading, and only cancel the request.
+ sslErrorName(error), sanitizeURL(errorUrl), error.getCertificate()));
+ if (errorUrl == null
+ // Ignore SSL errors from resources by comparing the main frame url with SSL
+ // error url.
+ || !errorUrl.equals(mainFrameUrl)) {
+ Log.d(TAG, "onReceivedSslError: mMainFrameUrl = " + mMainFrameUrl);
handler.cancel();
return;
}
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 9064ebe..4c9629d 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -58,8 +58,8 @@
manifest: "AndroidManifest.xml",
- owner: "google",
platform_apis: true,
+ product_specific: true,
certificate: "platform",
privileged: true,
@@ -82,4 +82,6 @@
],
plugins: ["dagger2-compiler-2.19"],
+
+ required: ["privapp_whitelist_com.android.systemui"],
}
diff --git a/packages/ExtServices/Android.mk b/packages/ExtServices/Android.mk
index 1133499..a06dd86 100644
--- a/packages/ExtServices/Android.mk
+++ b/packages/ExtServices/Android.mk
@@ -25,10 +25,6 @@
LOCAL_CERTIFICATE := platform
-LOCAL_AAPT_FLAGS := --shared-lib
-
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-
LOCAL_PROGUARD_FLAG_FILES := proguard.proguard
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index e47d53c..76e2fe7 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -78,6 +78,10 @@
</intent-filter>
</service>
+ <activity android:name=".notification.CopyCodeActivity"
+ android:exported="false"
+ android:theme="@android:style/Theme.NoDisplay"/>
+
<library android:name="android.ext.services"/>
</application>
diff --git a/packages/ExtServices/res/values/strings.xml b/packages/ExtServices/res/values/strings.xml
index a9a5450..de35441 100644
--- a/packages/ExtServices/res/values/strings.xml
+++ b/packages/ExtServices/res/values/strings.xml
@@ -24,4 +24,10 @@
<item>EDIT_DISTANCE</item>
<item>EXACT_MATCH</item>
</string-array>
+
+ <!-- Action chip to copy a one time code to the user's clipboard [CHAR LIMIT=NONE]-->
+ <string name="copy_code_desc">Copy \u201c<xliff:g id="code" example="12345">%1$s</xliff:g>\u201c</string>
+ <!-- Toast to display when text is copied to the device clipboard [CHAR LIMIT=64]-->
+ <string name="code_copied_to_clipboard">Code copied</string>
+
</resources>
diff --git a/packages/ExtServices/src/android/ext/services/notification/CopyCodeActivity.java b/packages/ExtServices/src/android/ext/services/notification/CopyCodeActivity.java
new file mode 100644
index 0000000..6708d4d
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/notification/CopyCodeActivity.java
@@ -0,0 +1,54 @@
+/*
+ * 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 android.ext.services.notification;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Intent;
+import android.ext.services.R;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+/**
+ * An activity that copies text in the Bundle.
+ */
+public class CopyCodeActivity extends Activity {
+ private static final String TAG = "CopyCodeActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ handleIntent();
+ finish();
+ }
+
+ private void handleIntent() {
+ String code = getIntent().getStringExtra(Intent.EXTRA_TEXT);
+ if (TextUtils.isEmpty(code)) {
+ Log.w(TAG, "handleIntent: empty code");
+ return;
+ }
+ ClipboardManager clipboardManager = getSystemService(ClipboardManager.class);
+ ClipData clipData = ClipData.newPlainText(null, code);
+ clipboardManager.setPrimaryClip(clipData);
+ Toast.makeText(getApplicationContext(), R.string.code_copied_to_clipboard,
+ Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 24fa87a..bf8a3fa 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -15,11 +15,15 @@
*/
package android.ext.services.notification;
+import android.annotation.Nullable;
import android.app.Notification;
+import android.app.PendingIntent;
import android.app.Person;
import android.app.RemoteAction;
import android.app.RemoteInput;
import android.content.Context;
+import android.content.Intent;
+import android.ext.services.R;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.Parcelable;
@@ -48,11 +52,12 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.stream.Collectors;
public class SmartActionsHelper {
- private static final String KEY_ACTION_TYPE = "action_type";
- private static final String KEY_ACTION_SCORE = "action_score";
+ static final String ENTITIES_EXTRAS = "entities-extras";
+ static final String KEY_ACTION_TYPE = "action_type";
+ static final String KEY_ACTION_SCORE = "action_score";
+ static final String KEY_TEXT = "text";
// If a notification has any of these flags set, it's inelgibile for actions being added.
private static final int FLAG_MASK_INELGIBILE_FOR_ACTIONS =
Notification.FLAG_ONGOING_EVENT
@@ -109,11 +114,25 @@
repliesScore.put(textReply, conversationAction.getConfidenceScore());
}
- ArrayList<Notification.Action> actions = conversationActions.stream()
- .filter(conversationAction -> conversationAction.getAction() != null)
- .map(action -> createNotificationAction(
- action.getAction(), action.getType(), action.getConfidenceScore()))
- .collect(Collectors.toCollection(ArrayList::new));
+ ArrayList<Notification.Action> actions = new ArrayList<>();
+ for (ConversationAction conversationAction : conversationActions) {
+ if (!TextUtils.isEmpty(conversationAction.getTextReply())) {
+ continue;
+ }
+ Notification.Action notificationAction;
+ if (conversationAction.getAction() == null) {
+ notificationAction =
+ createNotificationActionWithoutRemoteAction(conversationAction);
+ } else {
+ notificationAction = createNotificationActionFromRemoteAction(
+ conversationAction.getAction(),
+ conversationAction.getType(),
+ conversationAction.getConfidenceScore());
+ }
+ if (notificationAction != null) {
+ actions.add(notificationAction);
+ }
+ }
// Start a new session for logging if necessary.
if (!TextUtils.isEmpty(resultId)
@@ -127,6 +146,55 @@
}
/**
+ * Creates notification action from ConversationAction that does not come up a RemoteAction.
+ * It could happen because we don't have common intents for some actions, like copying text.
+ */
+ @Nullable
+ private Notification.Action createNotificationActionWithoutRemoteAction(
+ ConversationAction conversationAction) {
+ if (ConversationAction.TYPE_COPY.equals(conversationAction.getType())) {
+ return createCopyCodeAction(conversationAction);
+ }
+ return null;
+ }
+
+ @Nullable
+ private Notification.Action createCopyCodeAction(ConversationAction conversationAction) {
+ Bundle extras = conversationAction.getExtras();
+ if (extras == null) {
+ return null;
+ }
+ Bundle entitiesExtas = extras.getParcelable(ENTITIES_EXTRAS);
+ if (entitiesExtas == null) {
+ return null;
+ }
+ String code = entitiesExtas.getString(KEY_TEXT);
+ if (TextUtils.isEmpty(code)) {
+ return null;
+ }
+ String contentDescription = mContext.getString(R.string.copy_code_desc, code);
+ Intent intent = new Intent(mContext, CopyCodeActivity.class);
+ intent.putExtra(Intent.EXTRA_TEXT, code);
+
+ RemoteAction remoteAction = new RemoteAction(Icon.createWithResource(
+ mContext.getResources(),
+ com.android.internal.R.drawable.ic_menu_copy_material),
+ code,
+ contentDescription,
+ PendingIntent.getActivity(
+ mContext,
+ code.hashCode(),
+ intent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ ));
+
+ return createNotificationActionFromRemoteAction(
+ remoteAction,
+ ConversationAction.TYPE_COPY,
+ conversationAction.getConfidenceScore());
+ }
+
+ /**
* Returns whether the suggestion might be used in the notifications in SysUI.
* <p>
* Currently, NAS has no idea if suggestions will actually be used in the notification, and thus
@@ -292,7 +360,7 @@
mTextClassifier.onTextClassifierEvent(textClassifierEvent);
}
- private Notification.Action createNotificationAction(
+ private Notification.Action createNotificationActionFromRemoteAction(
RemoteAction remoteAction, String actionType, float score) {
Icon icon = remoteAction.shouldShowIcon()
? remoteAction.getIcon()
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
index a1fbc7b..3a7d799 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
@@ -36,6 +36,7 @@
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
import android.os.Process;
import android.service.notification.NotificationAssistantService;
import android.service.notification.StatusBarNotification;
@@ -419,6 +420,31 @@
assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_ACTIONS_SHOWN);
}
+ @Test
+ public void testCopyAction() {
+ Bundle extras = new Bundle();
+ Bundle entitiesExtras = new Bundle();
+ entitiesExtras.putString(SmartActionsHelper.KEY_TEXT, "12345");
+ extras.putParcelable(SmartActionsHelper.ENTITIES_EXTRAS, entitiesExtras);
+ ConversationAction conversationAction =
+ new ConversationAction.Builder(ConversationAction.TYPE_COPY)
+ .setExtras(extras)
+ .build();
+ when(mTextClassifier.suggestConversationActions(any(ConversationActions.Request.class)))
+ .thenReturn(
+ new ConversationActions(
+ Collections.singletonList(conversationAction), null));
+
+ Notification notification = createMessageNotification();
+ when(mStatusBarNotification.getNotification()).thenReturn(notification);
+ SmartActionsHelper.SmartSuggestions suggestions =
+ mSmartActionsHelper.suggest(createNotificationEntry());
+
+ assertThat(suggestions.actions).hasSize(1);
+ Notification.Action action = suggestions.actions.get(0);
+ assertThat(action.title).isEqualTo("12345");
+ }
+
private ZonedDateTime createZonedDateTimeFromMsUtc(long msUtc) {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(msUtc), ZoneOffset.systemDefault());
}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 190247a..8872147 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -25,6 +25,7 @@
":services-networkstack-shared-srcs",
],
static_libs: [
+ "ipmemorystore-client",
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
"datastallprotosnano",
diff --git a/packages/NetworkStack/jarjar-rules-shared.txt b/packages/NetworkStack/jarjar-rules-shared.txt
index a8c712a..7346b1a 100644
--- a/packages/NetworkStack/jarjar-rules-shared.txt
+++ b/packages/NetworkStack/jarjar-rules-shared.txt
@@ -8,12 +8,3 @@
rule android.net.DhcpResultsParcelable* @0
rule android.net.DhcpResults* android.net.networkstack.DhcpResults@1
rule android.net.LocalLog* android.net.networkstack.LocalLog@1
-
-# TODO: remove from framework dependencies, then remove here
-rule android.net.InterfaceConfigurationParcel* android.net.networkstack.InterfaceConfigurationParcel@1
-rule android.net.TetherStatsParcel* android.net.networkstack.TetherStatsParcel@1
-
-# Used by UidRange, which is used by framework classes such as NetworkCapabilities.
-rule android.net.UidRangeParcel* android.net.networkstack.UidRangeParcel@1
-# TODO: move TcpKeepalivePacketData to services.net and delete
-rule android.net.TcpKeepalivePacketDataParcelable* android.net.networkstack.TcpKeepalivePacketDataParcelable@1
\ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
new file mode 100644
index 0000000..475f826
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/NetworkStackIpMemoryStore.java
@@ -0,0 +1,42 @@
+/*
+ * 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 android.net;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+/**
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in the same module.
+ * @see com.android.server.connectivity.ipmemorystore.IpMemoryStoreService
+ * @hide
+ */
+public class NetworkStackIpMemoryStore extends IpMemoryStoreClient {
+ @NonNull private final IIpMemoryStore mService;
+
+ public NetworkStackIpMemoryStore(@NonNull final Context context,
+ @NonNull final IIpMemoryStore service) {
+ super(context);
+ mService = service;
+ }
+
+ @Override
+ @NonNull
+ protected IIpMemoryStore getService() {
+ return mService;
+ }
+}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index b1f6d24..b68fe23 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -18,8 +18,6 @@
import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable;
-import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
-import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
@@ -31,9 +29,9 @@
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkStackIpMemoryStore;
import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
-import android.net.ProxyInfoParcelable;
import android.net.RouteInfo;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.apf.ApfCapabilities;
@@ -64,6 +62,7 @@
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService.NetworkStackServiceManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -103,6 +102,7 @@
// One holds StateMachine logs and the other connectivity packet logs.
private static final ConcurrentHashMap<String, SharedLog> sSmLogs = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, LocalLog> sPktLogs = new ConcurrentHashMap<>();
+ private final NetworkStackIpMemoryStore mIpMemoryStore;
/**
* Dump all state machine and connectivity packet logs to the specified writer.
@@ -201,7 +201,7 @@
public void onProvisioningSuccess(LinkProperties newLp) {
log("onProvisioningSuccess({" + newLp + "})");
try {
- mCallback.onProvisioningSuccess(toStableParcelable(newLp));
+ mCallback.onProvisioningSuccess(newLp);
} catch (RemoteException e) {
log("Failed to call onProvisioningSuccess", e);
}
@@ -210,7 +210,7 @@
public void onProvisioningFailure(LinkProperties newLp) {
log("onProvisioningFailure({" + newLp + "})");
try {
- mCallback.onProvisioningFailure(toStableParcelable(newLp));
+ mCallback.onProvisioningFailure(newLp);
} catch (RemoteException e) {
log("Failed to call onProvisioningFailure", e);
}
@@ -219,7 +219,7 @@
public void onLinkPropertiesChange(LinkProperties newLp) {
log("onLinkPropertiesChange({" + newLp + "})");
try {
- mCallback.onLinkPropertiesChange(toStableParcelable(newLp));
+ mCallback.onLinkPropertiesChange(newLp);
} catch (RemoteException e) {
log("Failed to call onLinkPropertiesChange", e);
}
@@ -391,13 +391,14 @@
}
public IpClient(Context context, String ifName, IIpClientCallbacks callback,
- NetworkObserverRegistry observerRegistry) {
- this(context, ifName, callback, observerRegistry, new Dependencies());
+ NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager) {
+ this(context, ifName, callback, observerRegistry, nssManager, new Dependencies());
}
@VisibleForTesting
IpClient(Context context, String ifName, IIpClientCallbacks callback,
- NetworkObserverRegistry observerRegistry, Dependencies deps) {
+ NetworkObserverRegistry observerRegistry, NetworkStackServiceManager nssManager,
+ Dependencies deps) {
super(IpClient.class.getSimpleName() + "." + ifName);
Preconditions.checkNotNull(ifName);
Preconditions.checkNotNull(callback);
@@ -411,6 +412,8 @@
mShutdownLatch = new CountDownLatch(1);
mCm = mContext.getSystemService(ConnectivityManager.class);
mObserverRegistry = observerRegistry;
+ mIpMemoryStore =
+ new NetworkStackIpMemoryStore(context, nssManager.getIpMemoryStoreService());
sSmLogs.putIfAbsent(mInterfaceName, new SharedLog(MAX_LOG_RECORDS, mTag));
mLog = sSmLogs.get(mInterfaceName);
@@ -525,9 +528,9 @@
IpClient.this.setTcpBufferSizes(tcpBufferSizes);
}
@Override
- public void setHttpProxy(ProxyInfoParcelable proxyInfo) {
+ public void setHttpProxy(ProxyInfo proxyInfo) {
checkNetworkStackCallingPermission();
- IpClient.this.setHttpProxy(fromStableParcelable(proxyInfo));
+ IpClient.this.setHttpProxy(proxyInfo);
}
@Override
public void setMulticastFilter(boolean enabled) {
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 72955bb..19e9108 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -19,7 +19,6 @@
import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
-import static android.net.shared.NetworkParcelableUtil.fromStableParcelable;
import static com.android.server.util.PermissionUtil.checkDumpPermission;
import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
@@ -30,12 +29,13 @@
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.net.IIpMemoryStore;
+import android.net.IIpMemoryStoreCallbacks;
import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkStackConnector;
import android.net.Network;
-import android.net.NetworkParcelable;
import android.net.PrivateDnsConfigParcel;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
@@ -51,6 +51,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.ipmemorystore.IpMemoryStoreService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -88,7 +89,19 @@
return makeConnector(this);
}
- private static class NetworkStackConnector extends INetworkStackConnector.Stub {
+ /**
+ * An interface for internal clients of the network stack service that can return
+ * or create inline instances of the service it manages.
+ */
+ public interface NetworkStackServiceManager {
+ /**
+ * Get an instance of the IpMemoryStoreService.
+ */
+ IIpMemoryStore getIpMemoryStoreService();
+ }
+
+ private static class NetworkStackConnector extends INetworkStackConnector.Stub
+ implements NetworkStackServiceManager {
private static final int NUM_VALIDATION_LOG_LINES = 20;
private final Context mContext;
private final INetd mNetd;
@@ -96,6 +109,7 @@
private final ConnectivityManager mCm;
@GuardedBy("mIpClients")
private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
+ private final IpMemoryStoreService mIpMemoryStoreService;
private static final int MAX_VALIDATION_LOGS = 10;
@GuardedBy("mValidationLogs")
@@ -118,6 +132,7 @@
(IBinder) context.getSystemService(Context.NETD_SERVICE));
mObserverRegistry = new NetworkObserverRegistry();
mCm = context.getSystemService(ConnectivityManager.class);
+ mIpMemoryStoreService = new IpMemoryStoreService(context);
try {
mObserverRegistry.register(mNetd);
@@ -152,18 +167,16 @@
}
@Override
- public void makeNetworkMonitor(
- NetworkParcelable network, String name, INetworkMonitorCallbacks cb)
+ public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb)
throws RemoteException {
- final Network parsedNetwork = fromStableParcelable(network);
- final SharedLog log = addValidationLogs(parsedNetwork, name);
- final NetworkMonitor nm = new NetworkMonitor(mContext, cb, parsedNetwork, log);
+ final SharedLog log = addValidationLogs(network, name);
+ final NetworkMonitor nm = new NetworkMonitor(mContext, cb, network, log);
cb.onNetworkMonitorCreated(new NetworkMonitorImpl(nm));
}
@Override
public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
- final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry);
+ final IpClient ipClient = new IpClient(mContext, ifName, cb, mObserverRegistry, this);
synchronized (mIpClients) {
final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
@@ -180,6 +193,17 @@
}
@Override
+ public IIpMemoryStore getIpMemoryStoreService() {
+ return mIpMemoryStoreService;
+ }
+
+ @Override
+ public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb)
+ throws RemoteException {
+ cb.onIpMemoryStoreFetched(mIpMemoryStoreService);
+ }
+
+ @Override
protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout,
@Nullable String[] args) {
checkDumpPermission();
@@ -253,9 +277,9 @@
}
@Override
- public void notifyAcceptPartialConnectivity() {
+ public void setAcceptPartialConnectivity() {
checkNetworkStackCallingPermission();
- mNm.notifyAcceptPartialConnectivity();
+ mNm.setAcceptPartialConnectivity();
}
@Override
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index fc56da7..73b203c 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -72,7 +72,7 @@
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellSignalStrength;
-import android.telephony.NetworkRegistrationState;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
@@ -319,7 +319,8 @@
private final DnsStallDetector mDnsStallDetector;
private long mLastProbeTime;
// Set to true if data stall is suspected and reset to false after metrics are sent to statsd.
- private boolean mCollectDataStallMetrics = false;
+ private boolean mCollectDataStallMetrics;
+ private boolean mAcceptPartialConnectivity;
public NetworkMonitor(Context context, INetworkMonitorCallbacks cb, Network network,
SharedLog validationLog) {
@@ -386,10 +387,11 @@
}
/**
- * ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
- * NetworkMonitor should ignore the https probe.
+ * ConnectivityService notifies NetworkMonitor that the user already accepted partial
+ * connectivity previously, so NetworkMonitor can validate the network even if it has partial
+ * connectivity.
*/
- public void notifyAcceptPartialConnectivity() {
+ public void setAcceptPartialConnectivity() {
sendMessage(EVENT_ACCEPT_PARTIAL_CONNECTIVITY);
}
@@ -651,9 +653,11 @@
case EVENT_DNS_NOTIFICATION:
mDnsStallDetector.accumulateConsecutiveDnsTimeoutCount(message.arg1);
break;
+ // Set mAcceptPartialConnectivity to true and if network start evaluating or
+ // re-evaluating and get the result of partial connectivity, ProbingState will
+ // disable HTTPS probe and transition to EvaluatingPrivateDnsState.
case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
- mUseHttps = false;
- transitionTo(mEvaluatingPrivateDnsState);
+ mAcceptPartialConnectivity = true;
break;
default:
break;
@@ -849,6 +853,14 @@
// ignore any re-evaluation requests. After, restart the
// evaluation process via EvaluatingState#enter.
return (mEvaluateAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
+ // Disable HTTPS probe and transition to EvaluatingPrivateDnsState because:
+ // 1. Network is connected and finish the network validation.
+ // 2. NetworkMonitor detects network is partial connectivity and user accepts it.
+ case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
+ mAcceptPartialConnectivity = true;
+ mUseHttps = false;
+ transitionTo(mEvaluatingPrivateDnsState);
+ return HANDLED;
default:
return NOT_HANDLED;
}
@@ -1081,7 +1093,12 @@
logNetworkEvent(NetworkEvent.NETWORK_PARTIAL_CONNECTIVITY);
notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY,
probeResult.redirectUrl);
- transitionTo(mWaitingForNextProbeState);
+ if (mAcceptPartialConnectivity) {
+ mUseHttps = false;
+ transitionTo(mEvaluatingPrivateDnsState);
+ } else {
+ transitionTo(mWaitingForNextProbeState);
+ }
} else {
logNetworkEvent(NetworkEvent.NETWORK_VALIDATION_FAILED);
notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, probeResult.redirectUrl);
@@ -1615,12 +1632,12 @@
return;
}
// See if the data sub is registered for PS services on cell.
- final NetworkRegistrationState nrs = dataSs.getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS,
- AccessNetworkConstants.TransportType.WWAN);
+ final NetworkRegistrationInfo nri = dataSs.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
latencyBroadcast.putExtra(
NetworkMonitorUtils.EXTRA_CELL_ID,
- nrs == null ? null : nrs.getCellIdentity());
+ nri == null ? null : nri.getCellIdentity());
latencyBroadcast.putExtra(NetworkMonitorUtils.EXTRA_CONNECTIVITY_TYPE, TYPE_MOBILE);
} else {
return;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index bbecc63..4d4ceed 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
similarity index 98%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index d43dc6a..f801b35 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static android.net.ipmemorystore.Status.ERROR_DATABASE_CANNOT_BE_OPENED;
import static android.net.ipmemorystore.Status.ERROR_GENERIC;
import static android.net.ipmemorystore.Status.ERROR_ILLEGAL_ARGUMENT;
import static android.net.ipmemorystore.Status.SUCCESS;
-import static com.android.server.net.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
+import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,7 +40,6 @@
import android.net.ipmemorystore.SameL3NetworkResponse;
import android.net.ipmemorystore.Status;
import android.net.ipmemorystore.StatusParcelable;
-import android.net.ipmemorystore.Utils;
import android.os.RemoteException;
import android.util.Log;
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
similarity index 99%
rename from services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
index aa45400..38d5544 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/RelevanceUtils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RelevanceUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/core/java/android/net/ipmemorystore/Utils.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
similarity index 94%
rename from core/java/android/net/ipmemorystore/Utils.java
rename to packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
index b361aca..9cbf490 100644
--- a/core/java/android/net/ipmemorystore/Utils.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/Utils.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package android.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.ipmemorystore.Blob;
/** {@hide} */
public class Utils {
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index bd488ea..eee12d6 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -16,13 +16,10 @@
package android.net.ip;
-import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
@@ -54,6 +51,7 @@
import com.android.internal.R;
import com.android.server.NetworkObserver;
import com.android.server.NetworkObserverRegistry;
+import com.android.server.NetworkStackService;
import org.junit.Before;
import org.junit.Test;
@@ -93,6 +91,7 @@
@Mock private AlarmManager mAlarm;
@Mock private IpClient.Dependencies mDependencies;
@Mock private ContentResolver mContentResolver;
+ @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
private NetworkObserver mObserver;
private InterfaceParams mIfParams;
@@ -121,7 +120,8 @@
private IpClient makeIpClient(String ifname) throws Exception {
setTestInterfaceParams(ifname);
- final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, ifname, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(ifname, false);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(ifname);
ArgumentCaptor<NetworkObserver> arg = ArgumentCaptor.forClass(NetworkObserver.class);
@@ -145,8 +145,8 @@
public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
setTestInterfaceParams(null);
try {
- final IpClient ipc = new IpClient(
- mContext, null, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, null, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.shutdown();
fail();
} catch (NullPointerException npe) {
@@ -159,8 +159,8 @@
final String ifname = "lo";
setTestInterfaceParams(ifname);
try {
- final IpClient ipc = new IpClient(
- mContext, ifname, null, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, ifname, null, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.shutdown();
fail();
} catch (NullPointerException npe) {
@@ -171,16 +171,16 @@
@Test
public void testInvalidInterfaceDoesNotThrow() throws Exception {
setTestInterfaceParams(TEST_IFNAME);
- final IpClient ipc = new IpClient(
- mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.shutdown();
}
@Test
public void testInterfaceNotFoundFailsImmediately() throws Exception {
setTestInterfaceParams(null);
- final IpClient ipc = new IpClient(
- mContext, TEST_IFNAME, mCb, mObserverRegistry, mDependencies);
+ final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
+ mNetworkStackServiceManager, mDependencies);
ipc.startProvisioning(new ProvisioningConfiguration());
verify(mCb, times(1)).onProvisioningFailure(any());
ipc.shutdown();
@@ -207,8 +207,7 @@
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
- .onLinkPropertiesChange(argThat(
- lp -> fromStableParcelable(lp).equals(makeEmptyLinkProperties(iface))));
+ .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
}
@Test
@@ -253,15 +252,13 @@
mObserver.onInterfaceAddressUpdated(new LinkAddress(addresses[lastAddr]), iface);
LinkProperties want = linkproperties(links(addresses), routes(prefixes));
want.setInterfaceName(iface);
- verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(argThat(
- lp -> fromStableParcelable(lp).equals(want)));
+ verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
ipc.shutdown();
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
- .onLinkPropertiesChange(argThat(
- lp -> fromStableParcelable(lp).equals(makeEmptyLinkProperties(iface))));
+ .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
}
@Test
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index d93aef2..d732c4e 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -583,7 +583,7 @@
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
.notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY, null);
- nm.notifyAcceptPartialConnectivity();
+ nm.setAcceptPartialConnectivity();
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
.notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
similarity index 99%
rename from tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index be10680..d0e58b8 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
similarity index 97%
rename from tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
rename to packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
index 7413b914..3d3aabc 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/RelevanceUtilsTests.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/RelevanceUtilsTests.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
-import static com.android.server.net.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
+import static com.android.server.connectivity.ipmemorystore.RelevanceUtils.CAPPED_RELEVANCE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
diff --git a/packages/PackageInstaller/AndroidManifest.xml b/packages/PackageInstaller/AndroidManifest.xml
index 591cf70..a69b412 100644
--- a/packages/PackageInstaller/AndroidManifest.xml
+++ b/packages/PackageInstaller/AndroidManifest.xml
@@ -93,6 +93,7 @@
<activity android:name=".UninstallerActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
+ android:theme="@style/Theme.AlertDialogActivity.NoActionBar"
android:excludeFromRecents="true"
android:noHistory="true">
<intent-filter android:priority="1">
diff --git a/packages/PackageInstaller/res/values/themes.xml b/packages/PackageInstaller/res/values/themes.xml
index 6c8e4c5..b11d28b 100644
--- a/packages/PackageInstaller/res/values/themes.xml
+++ b/packages/PackageInstaller/res/values/themes.xml
@@ -24,4 +24,9 @@
<style name="Theme.AlertDialogActivity"
parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert" />
+ <style name="Theme.AlertDialogActivity.NoActionBar">
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
</resources>
diff --git a/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml b/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml
index 0eefd4b..7db6014 100644
--- a/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml
+++ b/packages/SettingsLib/EntityHeaderWidgets/res/values/styles.xml
@@ -31,7 +31,7 @@
</style>
<style name="AppEntitiesHeader.Text.Summary"
- parent="@android:style/TextAppearance.Material.Body1">
+ parent="@*android:style/TextAppearance.DeviceDefault.Body1">
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:textSize">14sp</item>
</style>
diff --git a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
index e27ae7d..da575db 100644
--- a/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
+++ b/packages/SettingsLib/LayoutPreference/res/layout/settings_entity_header.xml
@@ -21,6 +21,8 @@
style="@style/EntityHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:orientation="horizontal">
<LinearLayout
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 8529e3e..87b5b57 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -47,7 +48,16 @@
if (dpm == null) {
return null;
}
- ComponentName adminComponent = dpm.getProfileOwnerAsUser(user);
+
+ Context userContext;
+ try {
+ userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+
+ ComponentName adminComponent = userContext.getSystemService(
+ DevicePolicyManager.class).getProfileOwner();
if (adminComponent != null) {
return new EnforcedAdmin(adminComponent, enforcedRestriction, user);
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index bf97d77..c6a995cb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -113,6 +113,9 @@
<!-- Summary for Connected wifi network without internet -->
<string name="wifi_connected_no_internet">Connected, no internet</string>
+ <!-- Summary for connected wifi network with partial internet connectivity [CHAR LIMIT=50] -->
+ <string name="wifi_limited_connection">Limited connection</string>
+
<!-- Wi-Fi status indicating that the current network is connected, but has no internet access. -->
<string name="wifi_status_no_internet">No internet</string>
@@ -185,8 +188,12 @@
<!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_battery_level">Active, <xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected and active, showing remote device status and battery level for untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_active_battery_level_untethered">Active, L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
<!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level. [CHAR LIMIT=NONE] -->
<string name="bluetooth_battery_level"><xliff:g id="battery_level_as_percentage">%1$s</xliff:g> battery</string>
+ <!-- Connected devices settings. Message when Bluetooth is connected but not in use, showing remote device battery level for untethered headset. [CHAR LIMIT=NONE] -->
+ <string name="bluetooth_battery_level_untethered">L: <xliff:g id="battery_level_as_percentage" example="25%">%1$s</xliff:g> battery, R: <xliff:g id="battery_level_as_percentage" example="25%">%2$s</xliff:g> battery</string>
<!-- Connected devices settings. Message when Bluetooth is connected and active but no battery information, showing remote device status. [CHAR LIMIT=NONE] -->
<string name="bluetooth_active_no_battery_level">Active</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index c9fbc7b..d4d0519 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -128,12 +128,12 @@
// to protect access to these.
final ArrayList<Session> mSessions = new ArrayList<Session>();
final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
- final InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
+ private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
// Map: userid => (Map: package name => AppEntry)
final SparseArray<HashMap<String, AppEntry>> mEntriesMap =
new SparseArray<HashMap<String, AppEntry>>();
final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
- List<ApplicationInfo> mApplications = new ArrayList<ApplicationInfo>();
+ List<ApplicationInfo> mApplications = new ArrayList<>();
long mCurId = 1;
UUID mCurComputingSizeUuid;
String mCurComputingSizePkg;
@@ -166,7 +166,7 @@
/**
* Flags to configure the session to request various types of info.
*/
- @IntDef(prefix = { "FLAG_SESSION_" }, value = {
+ @IntDef(prefix = {"FLAG_SESSION_"}, value = {
FLAG_SESSION_REQUEST_HOME_APP,
FLAG_SESSION_REQUEST_ICONS,
FLAG_SESSION_REQUEST_SIZES,
@@ -174,7 +174,13 @@
FLAG_SESSION_REQUEST_LEANBACK_LAUNCHER
})
@Retention(RetentionPolicy.SOURCE)
- public @interface SessionFlags {}
+ public @interface SessionFlags {
+ }
+
+ @VisibleForTesting
+ void setInterestingConfigChanges(InterestingConfigChanges interestingConfigChanges) {
+ mInterestingConfigChanges = interestingConfigChanges;
+ }
public static final @SessionFlags int DEFAULT_SESSION_FLAGS =
FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
@@ -190,6 +196,7 @@
for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
mEntriesMap.put(userId, new HashMap<String, AppEntry>());
}
+
mThread = new HandlerThread("ApplicationsState.Loader",
Process.THREAD_PRIORITY_BACKGROUND);
mThread.start();
@@ -256,12 +263,14 @@
mPackageIntentReceiver = new PackageIntentReceiver();
mPackageIntentReceiver.registerReceiver();
}
- mApplications = new ArrayList<ApplicationInfo>();
+
+ final List<ApplicationInfo> prevApplications = mApplications;
+ mApplications = new ArrayList<>();
for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
try {
// If this user is new, it needs a map created.
if (mEntriesMap.indexOfKey(user.id) < 0) {
- mEntriesMap.put(user.id, new HashMap<String, AppEntry>());
+ mEntriesMap.put(user.id, new HashMap<>());
}
@SuppressWarnings("unchecked")
ParceledListSlice<ApplicationInfo> list =
@@ -279,14 +288,14 @@
// should completely reload the app entries.
clearEntries();
} else {
- for (int i=0; i<mAppEntries.size(); i++) {
+ for (int i = 0; i < mAppEntries.size(); i++) {
mAppEntries.get(i).sizeStale = true;
}
}
mHaveDisabledApps = false;
mHaveInstantApps = false;
- for (int i=0; i<mApplications.size(); i++) {
+ for (int i = 0; i < mApplications.size(); i++) {
final ApplicationInfo info = mApplications.get(i);
// Need to trim out any applications that are disabled by
// something different than the user.
@@ -312,8 +321,9 @@
entry.info = info;
}
}
- if (mAppEntries.size() > mApplications.size()) {
- // There are less apps now, some must have been uninstalled.
+
+ if (anyAppIsRemoved(prevApplications, mApplications)) {
+ // some apps have been uninstalled.
clearEntries();
}
mCurComputingSizePkg = null;
@@ -322,6 +332,82 @@
}
}
+ /* The original design is mAppEntries.size() > mApplications.size().
+ It's correct if there is only the owner user and only one app is removed.
+ Problem 1:
+ If there is a user profile, the size of mAppEntries < mApplications is normal because
+ the number of app entries on UI (mAppEntries) should be equal to the number of apps got
+ from PMS (mApplications).
+
+ owner only case:
+ mApplications: user 0: 191
+ mAppEntries : user 0: 191
+ total mAppEntries: 191, mApplications: 191
+ If an app is removed, cached mAppEntries: 191 , mApplications: 191 -> 190, it is detected
+ as the number of apps becomes less.
+
+ If there is a work profile, mAppEntries removes some apps that are not installed for the
+ owner user.
+
+ For example, in the following case, 6 apps are removed from mAppEntries for the owner.
+ mApplications: user 0: 197, user 10: 189 => total 386
+ mAppEntries : user 0: 191, user 10: 189 => total 380
+ If an app is removed, cached mAppEntries: 380 , mApplications: 386 -> 385, the size of
+ mAppEntries is still not larger than mApplications, then does not clear mAppEntries.
+
+ Problem 2:
+ If remove an app and add another app outside Settings (e.g. Play Store) and back to
+ Settings, the amount of apps are not changed, it causes the entries keep the removed app.
+
+ Another case, if adding more apps than removing apps (e.g. add 2 apps and remove 1 app),
+ the final number of apps (mApplications) is even increased,
+
+ Therefore, should not only count on number of apps to determine any app is removed.
+ Compare the change of applications instead.
+ */
+ private static boolean anyAppIsRemoved(List<ApplicationInfo> prevApplications,
+ List<ApplicationInfo> applications) {
+
+ // No cache
+ if (prevApplications.size() == 0) {
+ return false;
+ }
+
+ if (applications.size() < prevApplications.size()) {
+ return true;
+ }
+
+ // build package sets of all applications <userId, HashSet of packages>
+ final HashMap<String, HashSet<String>> packageMap = new HashMap<>();
+ for (ApplicationInfo application : applications) {
+ final String userId = String.valueOf(UserHandle.getUserId(application.uid));
+
+ HashSet<String> appPackages = packageMap.get(userId);
+ if (appPackages == null) {
+ appPackages = new HashSet<>();
+ packageMap.put(userId, appPackages);
+ }
+ if (hasFlag(application.flags, ApplicationInfo.FLAG_INSTALLED)) {
+ appPackages.add(application.packageName);
+ }
+ }
+
+ // detect any previous app is removed
+ for (ApplicationInfo prevApplication : prevApplications) {
+ if (!hasFlag(prevApplication.flags, ApplicationInfo.FLAG_INSTALLED)) {
+ continue;
+ }
+ final String userId = String.valueOf(UserHandle.getUserId(prevApplication.uid));
+
+ final HashSet<String> packagesSet = packageMap.get(userId);
+ if (packagesSet == null || !packagesSet.remove(prevApplication.packageName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
@VisibleForTesting
void clearEntries() {
for (int i = 0; i < mEntriesMap.size(); i++) {
@@ -346,7 +432,7 @@
if (!mResumed) {
return;
}
- for (int i=0; i<mSessions.size(); i++) {
+ for (int i = 0; i < mSessions.size(); i++) {
if (mSessions.get(i).mResumed) {
return;
}
@@ -449,7 +535,7 @@
if (DEBUG_LOCKING) Log.v(TAG, "sumCacheSizes about to acquire lock...");
synchronized (mEntriesMap) {
if (DEBUG_LOCKING) Log.v(TAG, "-> sumCacheSizes now has lock");
- for (int i=mAppEntries.size()-1; i>=0; i--) {
+ for (int i = mAppEntries.size() - 1; i >= 0; i--) {
sum += mAppEntries.get(i).cacheSize;
}
if (DEBUG_LOCKING) Log.v(TAG, "...sumCacheSizes releasing lock");
@@ -458,7 +544,7 @@
}
int indexOfApplicationInfoLocked(String pkgName, int userId) {
- for (int i=mApplications.size()-1; i>=0; i--) {
+ for (int i = mApplications.size() - 1; i >= 0; i--) {
ApplicationInfo appInfo = mApplications.get(i);
if (appInfo.packageName.equals(pkgName)
&& UserHandle.getUserId(appInfo.uid) == userId) {
@@ -642,7 +728,7 @@
return;
}
mActiveSessions.clear();
- for (int i=0; i<mSessions.size(); i++) {
+ for (int i = 0; i < mSessions.size(); i++) {
Session s = mSessions.get(i);
if (s.mResumed) {
mActiveSessions.add(new WeakReference<>(s));
@@ -784,7 +870,7 @@
ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
if (DEBUG) Log.i(TAG, "Rebuilding...");
- for (int i=0; i<apps.size(); i++) {
+ for (int i = 0; i < apps.size(); i++) {
AppEntry entry = apps.get(i);
if (entry != null && (filter == null || filter.filterApp(entry))) {
synchronized (mEntriesMap) {
@@ -954,7 +1040,7 @@
}
}
if (rebuildingSessions != null) {
- for (int i=0; i<rebuildingSessions.size(); i++) {
+ for (int i = 0; i < rebuildingSessions.size(); i++) {
rebuildingSessions.get(i).handleRebuildList();
}
}
@@ -1047,9 +1133,9 @@
// If we do not specify MATCH_DIRECT_BOOT_AWARE or
// MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
// according to the user's lock state. When the user is locked,
- // components
- // with ComponentInfo#directBootAware == false will be filtered. We should
- // explicitly include both direct boot aware and unaware components here.
+ // components with ComponentInfo#directBootAware == false will be
+ // filtered. W should explicitly include both direct boot aware and
+ // unaware component here.
List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
launchIntent,
PackageManager.MATCH_DISABLED_COMPONENTS
@@ -1128,8 +1214,10 @@
synchronized (mEntriesMap) {
if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES acquired lock");
if (mCurComputingSizePkg != null) {
- if (DEBUG_LOCKING) Log.v(TAG,
- "MSG_LOAD_SIZES releasing: currently computing");
+ if (DEBUG_LOCKING) {
+ Log.v(TAG,
+ "MSG_LOAD_SIZES releasing: currently computing");
+ }
return;
}
@@ -1181,8 +1269,10 @@
});
}
- if (DEBUG_LOCKING) Log.v(TAG,
- "MSG_LOAD_SIZES releasing: now computing");
+ if (DEBUG_LOCKING) {
+ Log.v(TAG,
+ "MSG_LOAD_SIZES releasing: now computing");
+ }
return;
}
}
@@ -1255,8 +1345,10 @@
entry.internalSizeStr = getSizeStr(entry.internalSize);
entry.externalSize = getTotalExternalSize(stats);
entry.externalSizeStr = getSizeStr(entry.externalSize);
- if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry
- + ": " + entry.sizeStr);
+ if (DEBUG) {
+ Log.i(TAG, "Set size of " + entry.label + " " + entry
+ + ": " + entry.sizeStr);
+ }
sizeChanged = true;
}
}
@@ -1299,9 +1391,11 @@
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(this, userFilter);
}
+
void unregisterReceiver() {
mContext.unregisterReceiver(this);
}
+
@Override
public void onReceive(Context context, Intent intent) {
String actionStr = intent.getAction();
@@ -1354,12 +1448,19 @@
public interface Callbacks {
void onRunningStateChanged(boolean running);
+
void onPackageListChanged();
+
void onRebuildComplete(ArrayList<AppEntry> apps);
+
void onPackageIconChanged();
+
void onPackageSizeChanged(String packageName);
+
void onAllSizesComputed();
+
void onLauncherInfoChanged();
+
void onLoadEntriesCompleted();
}
@@ -1491,6 +1592,7 @@
*/
public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
private final Collator sCollator = Collator.getInstance();
+
@Override
public int compare(AppEntry object1, AppEntry object2) {
int compareResult = sCollator.compare(object1.label, object2.label);
@@ -1504,6 +1606,7 @@
return compareResult;
}
}
+
return object1.info.uid - object2.info.uid;
}
};
@@ -1540,9 +1643,11 @@
public interface AppFilter {
void init();
+
default void init(Context context) {
init();
}
+
boolean filterApp(AppEntry info);
}
@@ -1697,7 +1802,8 @@
@Override
public boolean filterApp(AppEntry entry) {
return !AppUtils.isInstant(entry.info)
- && hasFlag(entry.info.privateFlags, ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
+ && hasFlag(entry.info.privateFlags,
+ ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS);
}
};
@@ -1707,7 +1813,7 @@
@Override
public void init(Context context) {
mHidePackageNames = context.getResources()
- .getStringArray(R.array.config_hideWhenDisabled_packageNames);
+ .getStringArray(R.array.config_hideWhenDisabled_packageNames);
}
@Override
@@ -1720,7 +1826,7 @@
if (!entry.info.enabled) {
return false;
} else if (entry.info.enabledSetting ==
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
return false;
}
}
@@ -1798,7 +1904,7 @@
@Override
public boolean filterApp(AppEntry entry) {
boolean isMusicApp;
- synchronized(entry) {
+ synchronized (entry) {
isMusicApp = entry.info.category == ApplicationInfo.CATEGORY_AUDIO;
}
return isMusicApp;
@@ -1813,7 +1919,7 @@
@Override
public boolean filterApp(AppEntry entry) {
boolean isMovieApp;
- synchronized(entry) {
+ synchronized (entry) {
isMovieApp = entry.info.category == ApplicationInfo.CATEGORY_VIDEO;
}
return isMovieApp;
@@ -1823,7 +1929,8 @@
public static final AppFilter FILTER_PHOTOS =
new AppFilter() {
@Override
- public void init() {}
+ public void init() {
+ }
@Override
public boolean filterApp(AppEntry entry) {
@@ -1838,7 +1945,8 @@
public static final AppFilter FILTER_OTHER_APPS =
new AppFilter() {
@Override
- public void init() {}
+ public void init() {
+ }
@Override
public boolean filterApp(AppEntry entry) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 081f8a0..bb8c8a6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,7 +1,6 @@
package com.android.settingslib.bluetooth;
import android.bluetooth.BluetoothClass;
-import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -10,7 +9,6 @@
import androidx.annotation.DrawableRes;
import com.android.settingslib.R;
-import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
import java.util.List;
@@ -51,38 +49,29 @@
public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
CachedBluetoothDevice cachedDevice) {
- return getBtClassDrawableWithDescription(context, cachedDevice, 1 /* iconScale */);
- }
-
- public static Pair<Drawable, String> getBtClassDrawableWithDescription(Context context,
- CachedBluetoothDevice cachedDevice, float iconScale) {
BluetoothClass btClass = cachedDevice.getBtClass();
- final int level = cachedDevice.getBatteryLevel();
if (btClass != null) {
switch (btClass.getMajorDeviceClass()) {
case BluetoothClass.Device.Major.COMPUTER:
return new Pair<>(getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_bt_laptop, level, iconScale),
+ com.android.internal.R.drawable.ic_bt_laptop),
context.getString(R.string.bluetooth_talkback_computer));
case BluetoothClass.Device.Major.PHONE:
return new Pair<>(
getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_phone, level,
- iconScale),
+ com.android.internal.R.drawable.ic_phone),
context.getString(R.string.bluetooth_talkback_phone));
case BluetoothClass.Device.Major.PERIPHERAL:
return new Pair<>(
- getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass),
- level, iconScale),
+ getBluetoothDrawable(context, HidProfile.getHidClassDrawable(btClass)),
context.getString(R.string.bluetooth_talkback_input_peripheral));
case BluetoothClass.Device.Major.IMAGING:
return new Pair<>(
getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_settings_print, level,
- iconScale),
+ com.android.internal.R.drawable.ic_settings_print),
context.getString(R.string.bluetooth_talkback_imaging));
default:
@@ -94,38 +83,33 @@
for (LocalBluetoothProfile profile : profiles) {
int resId = profile.getDrawableResource(btClass);
if (resId != 0) {
- return new Pair<>(getBluetoothDrawable(context, resId, level, iconScale), null);
+ return new Pair<>(getBluetoothDrawable(context, resId), null);
}
}
if (btClass != null) {
if (btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
return new Pair<>(
getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_bt_headset_hfp, level,
- iconScale),
+ com.android.internal.R.drawable.ic_bt_headset_hfp),
context.getString(R.string.bluetooth_talkback_headset));
}
if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP)) {
return new Pair<>(
getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_bt_headphones_a2dp, level,
- iconScale),
+ com.android.internal.R.drawable.ic_bt_headphones_a2dp),
context.getString(R.string.bluetooth_talkback_headphone));
}
}
return new Pair<>(
getBluetoothDrawable(context,
- com.android.internal.R.drawable.ic_settings_bluetooth, level, iconScale),
+ com.android.internal.R.drawable.ic_settings_bluetooth),
context.getString(R.string.bluetooth_talkback_bluetooth));
}
- public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId,
- int batteryLevel, float iconScale) {
- if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
- return BluetoothDeviceLayerDrawable.createLayerDrawable(context, resId, batteryLevel,
- iconScale);
- } else {
- return context.getDrawable(resId);
- }
+ /**
+ * Get bluetooth drawable by {@code resId}
+ */
+ public static Drawable getBluetoothDrawable(Context context, @DrawableRes int resId) {
+ return context.getDrawable(resId);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index ab95910..2405666 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -32,6 +32,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settingslib.R;
+import com.android.settingslib.Utils;
import java.util.ArrayList;
import java.util.Collection;
@@ -830,6 +831,8 @@
boolean a2dpConnected = true; // A2DP is connected
boolean hfpConnected = true; // HFP is connected
boolean hearingAidConnected = true; // Hearing Aid is connected
+ int leftBattery = -1;
+ int rightBattery = -1;
synchronized (mProfileLock) {
for (LocalBluetoothProfile profile : getProfiles()) {
@@ -877,8 +880,23 @@
int stringRes = R.string.bluetooth_pairing;
//when profile is connected, information would be available
if (profileConnected) {
+ // Update Meta data for connected device
+ if (Boolean.parseBoolean(
+ mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET))) {
+ try {
+ leftBattery = Integer.parseInt(
+ mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY));
+ rightBattery = Integer.parseInt(mDevice.getMetadata(
+ BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY));
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "Parse error for unthethered battery level.");
+ }
+ }
+
// Set default string with battery level in device connected situation.
- if (batteryLevelPercentageString != null) {
+ if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+ stringRes = R.string.bluetooth_battery_level_untethered;
+ } else if (batteryLevelPercentageString != null) {
stringRes = R.string.bluetooth_battery_level;
}
@@ -887,22 +905,36 @@
// 2. Headset device active with in-calling state.
// 3. A2DP device active without in-calling state.
if (a2dpConnected || hfpConnected || hearingAidConnected) {
- final boolean isOnCall =
- com.android.settingslib.Utils.isAudioModeOngoingCall(mContext);
+ final boolean isOnCall = Utils.isAudioModeOngoingCall(mContext);
if ((mIsActiveDeviceHearingAid)
|| (mIsActiveDeviceHeadset && isOnCall)
|| (mIsActiveDeviceA2dp && !isOnCall)) {
- stringRes = (batteryLevelPercentageString != null)
- ? R.string.bluetooth_active_battery_level
- : R.string.bluetooth_active_no_battery_level;
+ if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+ stringRes = R.string.bluetooth_active_battery_level_untethered;
+ } else if (batteryLevelPercentageString != null) {
+ stringRes = R.string.bluetooth_active_battery_level;
+ } else {
+ stringRes = R.string.bluetooth_active_no_battery_level;
+ }
}
}
}
- return (stringRes != R.string.bluetooth_pairing
- || getBondState() == BluetoothDevice.BOND_BONDING)
- ? mContext.getString(stringRes, batteryLevelPercentageString)
- : null;
+ if (stringRes != R.string.bluetooth_pairing
+ || getBondState() == BluetoothDevice.BOND_BONDING) {
+ if (isTwsBatteryAvailable(leftBattery, rightBattery)) {
+ return mContext.getString(stringRes, Utils.formatPercentage(leftBattery),
+ Utils.formatPercentage(rightBattery));
+ } else {
+ return mContext.getString(stringRes, batteryLevelPercentageString);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private boolean isTwsBatteryAvailable(int leftBattery, int rightBattery) {
+ return leftBattery >= 0 && rightBattery >= 0;
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
index bee1b3c..d28b00a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java
@@ -276,6 +276,12 @@
return null;
}
ensureMetadataNotStale(context);
+ final ActivityInfo activityInfo = getActivityInfo(context);
+ if (activityInfo == null) {
+ Log.w(TAG, "Cannot find ActivityInfo for " + getDescription());
+ return null;
+ }
+
int iconResId = mMetaData.getInt(META_DATA_PREFERENCE_ICON);
// Set the icon
if (iconResId == 0) {
@@ -283,11 +289,11 @@
// ICON_URI should be loaded in app UI when need the icon object. Handling IPC at this
// level is too complex because we don't have a strong threading contract for this class
if (!mMetaData.containsKey(META_DATA_PREFERENCE_ICON_URI)) {
- iconResId = getActivityInfo(context).icon;
+ iconResId = activityInfo.icon;
}
}
if (iconResId != 0) {
- return Icon.createWithResource(getActivityInfo(context).packageName, iconResId);
+ return Icon.createWithResource(activityInfo.packageName, iconResId);
} else {
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index da140aa..8c3fcc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -70,13 +70,18 @@
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
+ // Some device may not have HearingAidProfile, consider all situation to set active device.
boolean isConnected = false;
-
if (hapProfile != null && a2dpProfile != null) {
isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
- updateSummary(true);
- setConnectedRecord();
+ } else if (a2dpProfile != null) {
+ isConnected = a2dpProfile.setActiveDevice(null);
+ } else if (hapProfile != null) {
+ isConnected = hapProfile.setActiveDevice(null);
}
+ updateSummary(isConnected);
+ setConnectedRecord();
+
Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
return isConnected;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
index 3e3c039..83ef4f9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java
@@ -107,20 +107,22 @@
}
/**
- * Returns relative time for the given millis in the past, in a short format such as "2 days
- * ago", "5 hr. ago", "40 min. ago", or "29 sec. ago".
+ * Returns relative time for the given millis in the past with different format style.
+ * In a short format such as "2 days ago", "5 hr. ago", "40 min. ago", or "29 sec. ago".
+ * In a long format such as "2 days ago", "5 hours ago", "40 minutes ago" or "29 seconds ago".
*
* <p>The unit is chosen to have good information value while only using one unit. So 27 hours
* and 50 minutes would be formatted as "28 hr. ago", while 50 hours would be formatted as
* "2 days ago".
*
- * @param context the application context
- * @param millis the elapsed time in milli seconds
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
* @param withSeconds include seconds?
+ * @param formatStyle format style
* @return the formatted elapsed time
*/
public static CharSequence formatRelativeTime(Context context, double millis,
- boolean withSeconds) {
+ boolean withSeconds, RelativeDateTimeFormatter.Style formatStyle) {
final int seconds = (int) Math.floor(millis / 1000);
final RelativeUnit unit;
final int value;
@@ -144,9 +146,31 @@
final RelativeDateTimeFormatter formatter = RelativeDateTimeFormatter.getInstance(
ULocale.forLocale(locale),
null /* default NumberFormat */,
- RelativeDateTimeFormatter.Style.LONG,
+ formatStyle,
android.icu.text.DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE);
return formatter.format(value, RelativeDateTimeFormatter.Direction.LAST, unit);
}
+
+ /**
+ * Returns relative time for the given millis in the past, in a long format such as "2 days
+ * ago", "5 hours ago", "40 minutes ago" or "29 seconds ago".
+ *
+ * <p>The unit is chosen to have good information value while only using one unit. So 27 hours
+ * and 50 minutes would be formatted as "28 hr. ago", while 50 hours would be formatted as
+ * "2 days ago".
+ *
+ * @param context the application context
+ * @param millis the elapsed time in milli seconds
+ * @param withSeconds include seconds?
+ * @return the formatted elapsed time
+ * @deprecated use {@link #formatRelativeTime(Context, double, boolean,
+ * RelativeDateTimeFormatter.Style)} instead.
+ */
+ @Deprecated
+ public static CharSequence formatRelativeTime(Context context, double millis,
+ boolean withSeconds) {
+ return formatRelativeTime(context, millis, withSeconds,
+ RelativeDateTimeFormatter.Style.LONG);
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 800c401..3acbcd3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1424,6 +1424,9 @@
int id = context.getResources()
.getIdentifier("network_available_sign_in", "string", "android");
return context.getString(id);
+ } else if (nc.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
+ return context.getString(R.string.wifi_limited_connection);
} else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
return context.getString(R.string.wifi_connected_no_internet);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 2ab369c..5352936 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -11,6 +11,7 @@
package com.android.settingslib.wifi;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import android.content.Context;
@@ -158,6 +159,9 @@
if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
statusLabel = mContext.getString(R.string.wifi_status_sign_in_required);
return;
+ } else if (networkCapabilities.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)) {
+ statusLabel = mContext.getString(R.string.wifi_limited_connection);
+ return;
} else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
statusLabel = mContext.getString(R.string.wifi_status_no_internet);
return;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index a098ecc..b27efd0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -16,11 +16,17 @@
package com.android.settingslib.applications;
+import static android.os.UserHandle.MU_ENABLED;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.shadow.api.Shadow.extract;
@@ -40,10 +46,13 @@
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.text.TextUtils;
import android.util.IconDrawableFactory;
@@ -70,6 +79,7 @@
import org.robolectric.shadows.ShadowLooper;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@@ -82,6 +92,19 @@
private final static String HOME_PACKAGE_NAME = "com.android.home";
private final static String LAUNCHABLE_PACKAGE_NAME = "com.android.launchable";
+ private static final int PROFILE_USERID = 10;
+
+ private static final String PKG_1 = "PKG1";
+ private static final int OWNER_UID_1 = 1001;
+ private static final int PROFILE_UID_1 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_1);
+
+ private static final String PKG_2 = "PKG2";
+ private static final int OWNER_UID_2 = 1002;
+ private static final int PROFILE_UID_2 = UserHandle.getUid(PROFILE_USERID, OWNER_UID_2);
+
+ private static final String PKG_3 = "PKG3";
+ private static final int OWNER_UID_3 = 1003;
+
/** Class under test */
private ApplicationsState mApplicationsState;
private Session mSession;
@@ -171,7 +194,7 @@
storageStats.dataBytes = 20;
storageStats.cacheBytes = 30;
when(mStorageStatsManager.queryStatsForPackage(any(UUID.class),
- anyString(), any(UserHandle.class))).thenReturn(storageStats);
+ anyString(), any(UserHandle.class))).thenReturn(storageStats);
// Set up 3 installed apps, in which 1 is hidden module
final List<ApplicationInfo> infos = new ArrayList<>();
@@ -195,11 +218,16 @@
}
private ApplicationInfo createApplicationInfo(String packageName) {
+ return createApplicationInfo(packageName, 0);
+ }
+
+ private ApplicationInfo createApplicationInfo(String packageName, int uid) {
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.sourceDir = "foo";
appInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
appInfo.storageUuid = UUID.randomUUID();
appInfo.packageName = packageName;
+ appInfo.uid = uid;
return appInfo;
}
@@ -211,10 +239,14 @@
}
private void addApp(String packageName, int id) {
- ApplicationInfo appInfo = createApplicationInfo(packageName);
+ addApp(packageName, id, 0);
+ }
+
+ private void addApp(String packageName, int id, int userId) {
+ ApplicationInfo appInfo = createApplicationInfo(packageName, id);
AppEntry appEntry = createAppEntry(appInfo, id);
mApplicationsState.mAppEntries.add(appEntry);
- mApplicationsState.mEntriesMap.get(0).put(appInfo.packageName, appEntry);
+ mApplicationsState.mEntriesMap.get(userId).put(appInfo.packageName, appEntry);
}
private void processAllMessages() {
@@ -351,4 +383,328 @@
assertThat(mApplications.get(1).packageName).isEqualTo("test.package.3");
}
+ @Test
+ public void removeAndInstall_noWorkprofile_doResumeIfNeededLocked_shouldClearEntries()
+ throws RemoteException {
+ // scenario: only owner user
+ // (PKG_1, PKG_2) -> (PKG_2, PKG_3)
+ // PKG_1 is removed and PKG_3 is installed before app is resumed.
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ // Previous Applications:
+ ApplicationInfo appInfo;
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+ mApplicationsState.mApplications = prevAppList;
+
+ // Previous Entries:
+ // (PKG_1, PKG_2)
+ addApp(PKG_1, OWNER_UID_1, 0);
+ addApp(PKG_2, OWNER_UID_2, 0);
+
+ // latest Applications:
+ // (PKG_2, PKG_3)
+ final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ appList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_3, OWNER_UID_3);
+ appList.add(appInfo);
+ setupDoResumeIfNeededLocked(appList, null);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState).clearEntries();
+ }
+
+ @Test
+ public void noAppRemoved_noWorkprofile_doResumeIfNeededLocked_shouldNotClearEntries()
+ throws RemoteException {
+ // scenario: only owner user
+ // (PKG_1, PKG_2)
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+ mApplicationsState.mApplications = prevAppList;
+
+ // Previous Entries:
+ // (pk1, PKG_2)
+ addApp(PKG_1, OWNER_UID_1, 0);
+ addApp(PKG_2, OWNER_UID_2, 0);
+
+ // latest Applications:
+ // (PKG_2, PKG_3)
+ final ArrayList<ApplicationInfo> appList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ appList.add(appInfo);
+ setupDoResumeIfNeededLocked(appList, null);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState, never()).clearEntries();
+ }
+
+ @Test
+ public void removeProfileApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+ throws RemoteException {
+ if (!MU_ENABLED) {
+ return;
+ }
+ // [Preconditions]
+ // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+ // 2 apps (PKG_1, PKG_2) for non-owner.
+ //
+ // [Actions]
+ // profile user's PKG_2 is removed before resume
+ //
+ // Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2) -> (PKG_1)
+ //
+ // Previous Entries:
+ // owner - (PKG_2)
+ // profile - (PKG_1, PKG_2)
+
+ ShadowUserManager shadowUserManager = Shadow
+ .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ prevAppList.add(appInfo);
+
+ mApplicationsState.mApplications = prevAppList;
+ // Previous Entries:
+ // owner (PKG_2), profile (pk1, PKG_2)
+ // PKG_1 is not installed for owner, hence it's removed from entries
+ addApp(PKG_2, OWNER_UID_2, 0);
+ addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+ addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+ // latest Applications:
+ // owner (PKG_1, PKG_2), profile (PKG_1)
+ // owner's PKG_1 is still listed and is in non-installed state
+ // profile user's PKG_2 is removed by a user before resume
+ //owner
+ final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ ownerAppList.add(appInfo);
+ //profile
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ setupDoResumeIfNeededLocked(ownerAppList, new ArrayList<>(Arrays.asList(appInfo)));
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState).clearEntries();
+ }
+
+ @Test
+ public void removeOwnerApp_workprofileExists_doResumeIfNeededLocked_shouldClearEntries()
+ throws RemoteException {
+ if (!MU_ENABLED) {
+ return;
+ }
+ // [Preconditions]
+ // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+ // 2 apps (PKG_1, PKG_2) for non-owner.
+ //
+ // [Actions]
+ // Owner user's PKG_2 is removed before resume
+ //
+ // Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2) -> (PKG_1 - uninstalled, PKG_2 - uninstalled)
+ // profile - (PKG_1, PKG_2) -> (PKG_1, PKG_2)
+ //
+ // Previous Entries:
+ // owner - (PKG_2)
+ // profile - (PKG_1, PKG_2)
+
+ ShadowUserManager shadowUserManager = Shadow
+ .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ prevAppList.add(appInfo);
+
+ mApplicationsState.mApplications = prevAppList;
+
+ // Previous Entries:
+ // owner (PKG_2), profile (pk1, PKG_2)
+ // PKG_1 is not installed for owner, hence it's removed from entries
+ addApp(PKG_2, OWNER_UID_2, 0);
+ addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+ addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+ // latest Applications:
+ // owner (PKG_1 - uninstalled, PKG_2 - uninstalled), profile (PKG_1, PKG_2)
+ // owner's PKG_1, PKG_2 is still listed and is in non-installed state
+ // profile user's PKG_2 is removed before resume
+ //owner
+ final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+
+ //profile
+ final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ profileAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ profileAppList.add(appInfo);
+ setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState).clearEntries();
+ }
+
+ @Test
+ public void noAppRemoved_workprofileExists_doResumeIfNeededLocked_shouldNotClearEntries()
+ throws RemoteException {
+ if (!MU_ENABLED) {
+ return;
+ }
+ // [Preconditions]
+ // 2 apps (PKG_1, PKG_2) for owner, PKG_1 is not in installed state
+ // 2 apps (PKG_1, PKG_2) for non-owner.
+ //
+ // Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ //
+ // Previous Entries:
+ // owner - (PKG_2)
+ // profile - (PKG_1, PKG_2)
+
+ ShadowUserManager shadowUserManager = Shadow
+ .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+ shadowUserManager.addProfile(PROFILE_USERID, "profile");
+
+ ApplicationsState.sInstance = null;
+ mApplicationsState = spy(
+ ApplicationsState
+ .getInstance(RuntimeEnvironment.application, mock(IPackageManager.class)));
+
+ ApplicationInfo appInfo;
+ // Previous Applications:
+ // owner - (PKG_1 - uninstalled, PKG_2)
+ // profile - (PKG_1, PKG_2)
+ final ArrayList<ApplicationInfo> prevAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ prevAppList.add(appInfo);
+
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ prevAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ prevAppList.add(appInfo);
+
+ mApplicationsState.mApplications = prevAppList;
+ // Previous Entries:
+ // owner (PKG_2), profile (pk1, PKG_2)
+ // PKG_1 is not installed for owner, hence it's removed from entries
+ addApp(PKG_2, OWNER_UID_2, 0);
+ addApp(PKG_1, PROFILE_UID_1, PROFILE_USERID);
+ addApp(PKG_2, PROFILE_UID_2, PROFILE_USERID);
+
+ // latest Applications:
+ // owner (PKG_1 - uninstalled, PKG_2), profile (PKG_1, PKG_2)
+ // owner's PKG_1 is still listed and is in non-installed state
+
+ // owner
+ final ArrayList<ApplicationInfo> ownerAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, OWNER_UID_1);
+ appInfo.flags ^= ApplicationInfo.FLAG_INSTALLED;
+ ownerAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, OWNER_UID_2);
+ ownerAppList.add(appInfo);
+
+ // profile
+ final ArrayList<ApplicationInfo> profileAppList = new ArrayList<>();
+ appInfo = createApplicationInfo(PKG_1, PROFILE_UID_1);
+ profileAppList.add(appInfo);
+ appInfo = createApplicationInfo(PKG_2, PROFILE_UID_2);
+ profileAppList.add(appInfo);
+ setupDoResumeIfNeededLocked(ownerAppList, profileAppList);
+
+ mApplicationsState.doResumeIfNeededLocked();
+
+ verify(mApplicationsState, never()).clearEntries();
+ }
+
+ private void setupDoResumeIfNeededLocked(ArrayList<ApplicationInfo> ownerApps,
+ ArrayList<ApplicationInfo> profileApps)
+ throws RemoteException {
+
+ if (ownerApps != null) {
+ when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(0)))
+ .thenReturn(new ParceledListSlice<>(ownerApps));
+ }
+ if (profileApps != null) {
+ when(mApplicationsState.mIpm.getInstalledApplications(anyInt(), eq(PROFILE_USERID)))
+ .thenReturn(new ParceledListSlice<>(profileApps));
+ }
+ final InterestingConfigChanges configChanges = mock(InterestingConfigChanges.class);
+ when(configChanges.applyNewConfig(any(Resources.class))).thenReturn(false);
+ mApplicationsState.setInterestingConfigChanges(configChanges);
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
index 7a71551..b713e08 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/BluetoothUtilsTest.java
@@ -15,36 +15,55 @@
*/
package com.android.settingslib.bluetooth;
-import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
-import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothClass;
+import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.util.Pair;
-import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
-
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@RunWith(RobolectricTestRunner.class)
public class BluetoothUtilsTest {
- @Test
- public void testGetBluetoothDrawable_noBatteryLevel_returnSimpleDrawable() {
- final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
- RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
- BluetoothDevice.BATTERY_LEVEL_UNKNOWN, 1 /* iconScale */);
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ private Context mContext;
- assertThat(drawable).isNotInstanceOf(BluetoothDeviceLayerDrawable.class);
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
}
@Test
- public void testGetBluetoothDrawable_hasBatteryLevel_returnLayerDrawable() {
- final Drawable drawable = BluetoothUtils.getBluetoothDrawable(
- RuntimeEnvironment.application, com.android.internal.R.drawable.ic_bt_laptop,
- 10 /* batteryLevel */, 1 /* iconScale */);
+ public void getBtClassDrawableWithDescription_typePhone_returnPhoneDrawable() {
+ when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn(
+ BluetoothClass.Device.Major.PHONE);
+ final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
+ mContext, mCachedBluetoothDevice);
- assertThat(drawable).isInstanceOf(BluetoothDeviceLayerDrawable.class);
+ verify(mContext).getDrawable(com.android.internal.R.drawable.ic_phone);
}
-}
+
+ @Test
+ public void getBtClassDrawableWithDescription_typeComputer_returnComputerDrawable() {
+ when(mCachedBluetoothDevice.getBtClass().getMajorDeviceClass()).thenReturn(
+ BluetoothClass.Device.Major.COMPUTER);
+ final Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
+ mContext, mCachedBluetoothDevice);
+
+ verify(mContext).getDrawable(com.android.internal.R.drawable.ic_bt_laptop);
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4e5d38a..79b84b9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -41,14 +41,16 @@
@RunWith(RobolectricTestRunner.class)
public class CachedBluetoothDeviceTest {
- private final static String DEVICE_NAME = "TestName";
- private final static String DEVICE_ALIAS = "TestAlias";
- private final static String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
- private final static String DEVICE_ALIAS_NEW = "TestAliasNew";
- private final static short RSSI_1 = 10;
- private final static short RSSI_2 = 11;
- private final static boolean JUSTDISCOVERED_1 = true;
- private final static boolean JUSTDISCOVERED_2 = false;
+ private static final String DEVICE_NAME = "TestName";
+ private static final String DEVICE_ALIAS = "TestAlias";
+ private static final String DEVICE_ADDRESS = "AA:BB:CC:DD:EE:FF";
+ private static final String DEVICE_ALIAS_NEW = "TestAliasNew";
+ private static final String TWS_BATTERY_LEFT = "15";
+ private static final String TWS_BATTERY_RIGHT = "25";
+ private static final short RSSI_1 = 10;
+ private static final short RSSI_2 = 11;
+ private static final boolean JUSTDISCOVERED_1 = true;
+ private static final boolean JUSTDISCOVERED_2 = false;
@Mock
private LocalBluetoothProfileManager mProfileManager;
@Mock
@@ -447,6 +449,41 @@
}
@Test
+ public void getConnectionSummary_trueWirelessActiveDeviceWithBattery_returnActiveWithBattery() {
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+ "true");
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+ TWS_BATTERY_LEFT);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+ TWS_BATTERY_RIGHT);
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+ "Active, L: 15% battery, R: 25% battery");
+ }
+
+ @Test
+ public void getConnectionSummary_trueWirelessDeviceWithBattery_returnActiveWithBattery() {
+ updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+ updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTHETHERED_HEADSET)).thenReturn(
+ "true");
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_LEFT_BATTERY)).thenReturn(
+ TWS_BATTERY_LEFT);
+ when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTHETHERED_RIGHT_BATTERY)).thenReturn(
+ TWS_BATTERY_RIGHT);
+
+ assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+ "L: 15% battery, R: 25% battery");
+ }
+
+ @Test
public void getCarConnectionSummary_singleProfileConnectDisconnect() {
// Test without battery level
// Set PAN profile to be connected and test connection state summary
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 50a6a9d..0752dc0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -100,6 +100,30 @@
}
@Test
+ public void connect_hearingAidProfileIsNullAndA2dpProfileNotNull_isConnectedReturnTrue() {
+ when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null);
+
+ when(mA2dpProfile.setActiveDevice(null)).thenReturn(true);
+ assertThat(mPhoneMediaDevice.connect()).isTrue();
+ }
+
+ @Test
+ public void connect_hearingAidProfileNotNullAndA2dpProfileIsNull_isConnectedReturnTrue() {
+ when(mLocalProfileManager.getA2dpProfile()).thenReturn(null);
+
+ when(mHapProfile.setActiveDevice(null)).thenReturn(true);
+ assertThat(mPhoneMediaDevice.connect()).isTrue();
+ }
+
+ @Test
+ public void connect_hearingAidProfileAndA2dpProfileIsNull_isConnectedReturnFalse() {
+ when(mLocalProfileManager.getA2dpProfile()).thenReturn(null);
+ when(mLocalProfileManager.getHearingAidProfile()).thenReturn(null);
+
+ assertThat(mPhoneMediaDevice.connect()).isFalse();
+ }
+
+ @Test
public void updateSummary_isActiveIsTrue_returnActiveString() {
mPhoneMediaDevice.updateSummary(true);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
index c50d646..ca1eefc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowUserManager.java
@@ -29,6 +29,7 @@
@Implements(value = UserManager.class)
public class ShadowUserManager extends org.robolectric.shadows.ShadowUserManager {
+ private List<UserInfo> mUserInfos = addProfile(0, "Owner");
@Implementation
protected static UserManager get(Context context) {
@@ -37,16 +38,24 @@
@Implementation
protected int[] getProfileIdsWithDisabled(int userId) {
- return new int[]{0};
+ return mUserInfos.stream().mapToInt(s -> s.id).toArray();
}
@Implementation
protected List<UserInfo> getProfiles() {
- UserInfo userInfo = new UserInfo();
- userInfo.id = 0;
- List<UserInfo> userInfos = new ArrayList<>();
- userInfos.add(userInfo);
- return userInfos;
+ return mUserInfos;
+ }
+
+ public List<UserInfo> addProfile(int id, String name) {
+ List<UserInfo> userInfoList = mUserInfos;
+ if (userInfoList == null) {
+ userInfoList = new ArrayList<>();
+ }
+ final UserInfo userInfo = new UserInfo();
+ userInfo.id = id;
+ userInfo.name = name;
+ userInfoList.add(userInfo);
+ return userInfoList;
}
@Implementation
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
index 8fbbfbb..b503972 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Mockito.spy;
import android.content.Context;
+import android.icu.text.RelativeDateTimeFormatter;
import android.text.SpannableStringBuilder;
import android.text.format.DateUtils;
import android.text.style.TtsSpan;
@@ -116,8 +117,8 @@
final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
final String expectedTime = "Just now";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -125,8 +126,8 @@
final double testMillis = 40 * DateUtils.SECOND_IN_MILLIS;
final String expectedTime = "1 minute ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -134,8 +135,8 @@
final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
final String expectedTime = "Just now";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -143,8 +144,8 @@
final double testMillis = 119 * DateUtils.SECOND_IN_MILLIS;
final String expectedTime = "2 minutes ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -152,8 +153,8 @@
final double testMillis = 2 * DateUtils.MINUTE_IN_MILLIS;
final String expectedTime = "2 minutes ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -161,8 +162,8 @@
final double testMillis = 119 * DateUtils.MINUTE_IN_MILLIS;
final String expectedTime = "119 minutes ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -170,8 +171,8 @@
final double testMillis = 2 * DateUtils.HOUR_IN_MILLIS;
final String expectedTime = "2 hours ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -179,8 +180,8 @@
final double testMillis = 47 * DateUtils.HOUR_IN_MILLIS;
final String expectedTime = "47 hours ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -188,8 +189,8 @@
final double testMillis = 2 * DateUtils.DAY_IN_MILLIS;
final String expectedTime = "2 days ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -197,8 +198,8 @@
final double testMillis = 0;
final String expectedTime = "Just now";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, true,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
@Test
@@ -206,7 +207,7 @@
final double testMillis = 0;
final String expectedTime = "0 minutes ago";
- assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false).toString()).isEqualTo(
- expectedTime);
+ assertThat(StringUtil.formatRelativeTime(mContext, testMillis, false,
+ RelativeDateTimeFormatter.Style.LONG).toString()).isEqualTo(expectedTime);
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7c8aa09..441f88c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -86,6 +86,7 @@
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_ROLLBACKS" />
+ <uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
index e1bf6cb..5da7611 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_message_area.xml
@@ -17,15 +17,24 @@
*/
-->
-<!-- This contains emergency call button and carrier as shared by pin/pattern/password screens -->
-<com.android.keyguard.KeyguardMessageArea
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- style="@style/Keyguard.TextView"
- android:id="@+id/keyguard_message_area"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:focusable="true" />
-
+<!-- This contains error message field and padlock shared by pin/pattern/password screens -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
+ <FrameLayout
+ android:id="@+id/lock_icon_container"
+ android:layout_gravity="center"
+ android:layout_marginBottom="@dimen/keyguard_lock_padding"
+ android:layout_width="@dimen/keyguard_lock_width"
+ android:layout_height="@dimen/keyguard_lock_height" />
+ <com.android.keyguard.KeyguardMessageArea
+ android:id="@+id/keyguard_message_area"
+ style="@style/Keyguard.TextView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:focusable="true" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
index 38d2ecc3..91ca5c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw320dp/dimens.xml
@@ -21,6 +21,6 @@
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">345dp</dimen>
+ <dimen name="keyguard_security_height">395dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
index 90c4795..d7c9975 100644
--- a/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw360dp/dimens.xml
@@ -21,5 +21,5 @@
<!-- Height of the sliding KeyguardSecurityContainer (includes 2x
keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">400dp</dimen>
+ <dimen name="keyguard_security_height">450dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
index 9ea04dc..a3c37e4 100644
--- a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
@@ -20,5 +20,5 @@
<resources>
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">500dp</dimen>
+ <dimen name="keyguard_security_height">550dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
index 9157822..1dc61c5 100644
--- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
@@ -20,7 +20,7 @@
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">420dp</dimen>
+ <dimen name="keyguard_security_height">470dp</dimen>
<dimen name="widget_big_font_size">100dp</dimen>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index b6a41c1..d67c98a 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -27,11 +27,11 @@
<!-- Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_height">400dp</dimen>
+ <dimen name="keyguard_security_height">450dp</dimen>
<!-- Max Height of the sliding KeyguardSecurityContainer
(includes 2x keyguard_security_view_top_margin) -->
- <dimen name="keyguard_security_max_height">455dp</dimen>
+ <dimen name="keyguard_security_max_height">505dp</dimen>
<!-- Margin around the various security views -->
<dimen name="keyguard_security_view_top_margin">8dp</dimen>
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index 1e8cd5a..83557f2 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -39,152 +39,158 @@
android:layout_height="0dp"
android:layout_weight="1" />
- <LinearLayout
+ <ScrollView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
-
- <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
- on horizontal/portrait orientation -->
- <View
- android:id="@+id/left_space"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent"/>
+ android:layout_height="wrap_content">
<LinearLayout
- android:id="@+id/dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:background="@drawable/biometric_dialog_bg"
- android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
- android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
- android:layout_marginRight="@dimen/biometric_dialog_border_padding">
+ android:orientation="horizontal">
- <TextView
- android:id="@+id/title"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="24dp"
- android:layout_marginStart="24dp"
- android:layout_marginTop="24dp"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:textSize="20sp"
- android:maxLines="1"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:textColor="?android:attr/textColorPrimary"/>
+ <!-- This is not a Space since Spaces cannot be clicked. The width of this changes
+ depending on horizontal/portrait orientation -->
+ <View
+ android:id="@+id/left_space"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="24dp"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:textSize="16sp"
- android:maxLines="1"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:textColor="?android:attr/textColorPrimary"/>
+ <LinearLayout
+ android:id="@+id/dialog"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="@drawable/biometric_dialog_bg"
+ android:layout_marginBottom="@dimen/biometric_dialog_border_padding"
+ android:layout_marginLeft="@dimen/biometric_dialog_border_padding"
+ android:layout_marginRight="@dimen/biometric_dialog_border_padding">
- <TextView
- android:id="@+id/description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="24dp"
- android:layout_marginStart="24dp"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:paddingTop="8dp"
- android:textSize="16sp"
- android:maxLines="4"
- android:textColor="?android:attr/textColorPrimary"/>
+ <TextView
+ android:id="@+id/title"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="24dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginTop="24dp"
+ android:gravity="@integer/biometric_dialog_text_gravity"
+ android:textSize="20sp"
+ android:maxLines="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:textColor="?android:attr/textColorPrimary"/>
- <ImageView
- android:id="@+id/biometric_icon"
- android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
- android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
- android:layout_gravity="center_horizontal"
- android:layout_marginTop="48dp"
- android:scaleType="fitXY" />
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="24dp"
+ android:gravity="@integer/biometric_dialog_text_gravity"
+ android:textSize="16sp"
+ android:maxLines="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:marqueeRepeatLimit="marquee_forever"
+ android:textColor="?android:attr/textColorPrimary"/>
- <TextView
- android:id="@+id/error"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginEnd="24dp"
- android:layout_marginStart="24dp"
- android:paddingTop="16dp"
- android:paddingBottom="24dp"
- android:textSize="12sp"
- android:gravity="center_horizontal"
- android:accessibilityLiveRegion="polite"
- android:contentDescription="@string/accessibility_biometric_dialog_help_area"
- android:textColor="?android:attr/textColorSecondary"/>
+ <TextView
+ android:id="@+id/description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="24dp"
+ android:layout_marginStart="24dp"
+ android:gravity="@integer/biometric_dialog_text_gravity"
+ android:paddingTop="8dp"
+ android:textSize="16sp"
+ android:maxLines="4"
+ android:textColor="?android:attr/textColorPrimary"/>
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="72dip"
- android:paddingTop="24dp"
- android:layout_gravity="center_vertical"
- style="?android:attr/buttonBarStyle"
- android:orientation="horizontal"
- android:measureWithLargestChild="true">
- <Space android:id="@+id/leftSpacer"
- android:layout_width="12dp"
- android:layout_height="match_parent"
- android:visibility="visible" />
- <!-- Negative Button -->
- <Button android:id="@+id/button2"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:gravity="center"
- android:maxLines="2" />
- <Space android:id="@+id/middleSpacer"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:visibility="visible" />
- <!-- Positive Button -->
- <Button android:id="@+id/button1"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:gravity="center"
- android:maxLines="2"
- android:text="@string/biometric_dialog_confirm"
- android:visibility="gone"/>
- <!-- Try Again Button -->
- <Button android:id="@+id/button_try_again"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:gravity="center"
- android:maxLines="2"
- android:text="@string/biometric_dialog_try_again"
- android:visibility="gone"/>
- <Space android:id="@+id/rightSpacer"
- android:layout_width="12dip"
- android:layout_height="match_parent"
- android:visibility="visible" />
- </LinearLayout>
+ <ImageView
+ android:id="@+id/biometric_icon"
+ android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
+ android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="48dp"
+ android:scaleType="fitXY" />
+
+ <TextView
+ android:id="@+id/error"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="24dp"
+ android:layout_marginStart="24dp"
+ android:paddingTop="16dp"
+ android:paddingBottom="24dp"
+ android:textSize="12sp"
+ android:gravity="center_horizontal"
+ android:accessibilityLiveRegion="polite"
+ android:contentDescription="@string/accessibility_biometric_dialog_help_area"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="72dip"
+ android:paddingTop="24dp"
+ android:layout_gravity="center_vertical"
+ style="?android:attr/buttonBarStyle"
+ android:orientation="horizontal"
+ android:measureWithLargestChild="true">
+ <Space android:id="@+id/leftSpacer"
+ android:layout_width="12dp"
+ android:layout_height="match_parent"
+ android:visibility="visible" />
+ <!-- Negative Button -->
+ <Button android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
+ android:gravity="center"
+ android:maxLines="2" />
+ <Space android:id="@+id/middleSpacer"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:visibility="visible" />
+ <!-- Positive Button -->
+ <Button android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ style="@*android:style/Widget.DeviceDefault.Button.Colored"
+ android:gravity="center"
+ android:maxLines="2"
+ android:text="@string/biometric_dialog_confirm"
+ android:visibility="gone"/>
+ <!-- Try Again Button -->
+ <Button android:id="@+id/button_try_again"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ style="@*android:style/Widget.DeviceDefault.Button.Colored"
+ android:gravity="center"
+ android:maxLines="2"
+ android:text="@string/biometric_dialog_try_again"
+ android:visibility="gone"/>
+ <Space android:id="@+id/rightSpacer"
+ android:layout_width="12dip"
+ android:layout_height="match_parent"
+ android:visibility="visible" />
+ </LinearLayout>
+ </LinearLayout>
+
+ <!-- This is not a Space since Spaces cannot be clicked. The width of this changes
+ depending on horizontal/portrait orientation -->
+ <View
+ android:id="@+id/right_space"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent" />
+
</LinearLayout>
- <!-- This is not a Space since Spaces cannot be clicked. The width of this changes depending
- on horizontal/portrait orientation -->
- <View
- android:id="@+id/right_space"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
-
- </LinearLayout>
+ </ScrollView>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/global_actions_grid.xml b/packages/SystemUI/res/layout/global_actions_grid.xml
index d90d5e9..8651e5a 100644
--- a/packages/SystemUI/res/layout/global_actions_grid.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid.xml
@@ -31,7 +31,6 @@
android:paddingTop="@dimen/global_actions_grid_vertical_padding"
android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
android:orientation="vertical"
- android:background="?android:attr/colorBackgroundFloating"
android:gravity="center"
android:translationZ="@dimen/global_actions_translate"
/>
@@ -48,7 +47,6 @@
android:paddingRight="@dimen/global_actions_grid_horizontal_padding"
android:paddingTop="@dimen/global_actions_grid_vertical_padding"
android:paddingBottom="@dimen/global_actions_grid_vertical_padding"
- android:background="?android:attr/colorBackgroundFloating"
>
<LinearLayout
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index 6c5c7fa..3d63b7d 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -5,26 +5,25 @@
android:clipChildren="false"
android:clipToPadding="false"
android:gravity="top"
- android:orientation="vertical">
-
- <Space
- android:layout_width="match_parent"
- android:layout_height="10dp"/>
+ android:orientation="vertical"
+ android:padding="@dimen/global_actions_padding"
+ android:background="@drawable/rounded_bg_full">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical"
- android:background="@android:color/white">
+ android:orientation="vertical">
<CheckBox
android:id="@+id/checkbox_mic"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/screenrecord_mic_label"/>
<CheckBox
android:id="@+id/checkbox_taps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/screenrecord_taps_label"/>
<Button
android:id="@+id/record_button"
@@ -34,8 +33,4 @@
/>
</LinearLayout>
- <Space
- android:layout_width="match_parent"
- android:layout_height="10dp"/>
-
</LinearLayout>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 5803bf1..d74d258 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -47,4 +47,16 @@
<!-- The color of the background in the bottom part of QSCustomizer -->
<color name="qs_customize_decoration">@color/GM2_grey_800</color>
+
+ <!-- The color of the background in the separated list of the Global Actions menu -->
+ <color name="global_actions_separated_background">@color/GM2_grey_900</color>
+
+ <!-- The color of the background in the grid of the Global Actions menu -->
+ <color name="global_actions_grid_background">@color/GM2_grey_800</color>
+
+ <!-- The color of the text in the Global Actions menu -->
+ <color name="global_actions_text">@color/GM2_grey_200</color>
+
+ <!-- The color of the text in the Global Actions menu -->
+ <color name="global_actions_alert_text">@color/GM2_red_300</color>
</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 0fed96e..27d2bcd 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -18,8 +18,6 @@
<declare-styleable name="KeyButtonView">
<!-- key code to send when pressed; if absent or 0, no key is sent -->
<attr name="keyCode" format="integer" />
- <!-- does this button generate longpress / repeat events? -->
- <attr name="keyRepeat" format="boolean" />
<!-- Should this button play sound effects, default true -->
<attr name="playSound" format="boolean" />
<attr name="android:contentDescription" />
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0e4ffee..b82c250 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -38,6 +38,18 @@
<color name="qs_customize_background">@color/GM2_grey_50</color>
<color name="qs_customize_decoration">@color/GM2_grey_100</color>
+ <!-- The color of the background in the separated list of the Global Actions menu -->
+ <color name="global_actions_separated_background">@color/GM2_grey_300</color>
+
+ <!-- The color of the background in the grid of the Global Actions menu -->
+ <color name="global_actions_grid_background">@color/GM2_grey_200</color>
+
+ <!-- The color of the text in the Global Actions menu -->
+ <color name="global_actions_text">@color/GM2_grey_900</color>
+
+ <!-- The color of the text in the Global Actions menu -->
+ <color name="global_actions_alert_text">@color/GM2_red_500</color>
+
<!-- Tint color for the content on the notification overflow card. -->
<color name="keyguard_overflow_content_color">#ff686868</color>
@@ -149,4 +161,7 @@
<color name="GM2_grey_700">#5F6368</color>
<color name="GM2_grey_800">#3C4043</color>
<color name="GM2_grey_900">#202124</color>
+
+ <color name="GM2_red_300">#F28B82</color>
+ <color name="GM2_red_500">#B71C1C</color>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index da43391..44fb141 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1069,10 +1069,10 @@
<string name="battery_saver_notification_action_text">Turn off Battery Saver</string>
<!-- Media projection permission dialog warning text. [CHAR LIMIT=NONE] -->
- <string name="media_projection_dialog_text"><xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> will start capturing everything on your screen including notifications, passwords, photos, messages and payment information.</string>
+ <string name="media_projection_dialog_text">While recording or casting, <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> can capture any sensitive information, such as audio that you play and your passwords, payment info, photos, and messages.</string>
<!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] -->
- <string name="media_projection_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g> to record or cast your screen?</string>
+ <string name="media_projection_dialog_title">Exposing sensitive info during casting/recording </string>
<!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] -->
<string name="media_projection_remember_text">Don\'t show again</string>
@@ -2370,12 +2370,29 @@
<string name="bubbles_deep_link_button_description">Open <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
<!-- Text used for content description of settings button in the header of expanded bubble
view. [CHAR_LIMIT=NONE] -->
- <string name="bubbles_settings_button_description">Open notification settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
+ <string name="bubbles_settings_button_description">Settings for <xliff:g id="app_name" example="YouTube">%1$s</xliff:g> bubbles</string>
<!-- Text for asking the user whether bubbles (floating app content) should be enabled for an
app. [CHAR LIMIT=NONE] -->
- <string name="bubbles_prompt">Allow bubbles from this app?</string>
+ <string name="bubbles_prompt">Allow bubbles from <xliff:g id="app_name" example="YouTube">%1$s</xliff:g>?</string>
<!-- Text used for button allowing user to opt out of bubbles [CHAR LIMIT=20] -->
- <string name="no_bubbles">Block</string>
+ <string name="no_bubbles">Deny</string>
<!-- Text used for button allowing user to approve / enable bubbles [CHAR LIMIT=20] -->
<string name="yes_bubbles">Allow</string>
+ <!-- Text used for the button allowing users to postpone their decision to allow or deny bubbles [CHAR LIMIT=40] -->
+ <string name="ask_me_later_bubbles">Ask me later</string>
+ <!-- Content description when a bubble is focused. [CHAR LIMIT=NONE] -->
+ <string name="bubble_content_description_single"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
+ <!-- Content description when the stack of bubbles is focused. [CHAR LIMIT=NONE] -->
+ <string name="bubble_content_description_stack"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g> and <xliff:g id="bubble_count" example="4">%3$d</xliff:g> more</string>
+ <!-- Action in accessibility menu to move the stack of bubbles [CHAR LIMIT=20] -->
+ <string name="bubble_accessibility_action_move">Move</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the top left of the screen. [CHAR LIMIT=30] -->
+ <string name="bubble_accessibility_action_move_top_left">Move top left</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the top right of the screen. [CHAR LIMIT=30] -->
+ <string name="bubble_accessibility_action_move_top_right">Move top right</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the bottom left of the screen. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
+ <!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
+ <string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
+
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 0f71ffb..6b07ed8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -219,6 +219,7 @@
IRecentsAnimationRunner runner = null;
if (animationHandler != null) {
runner = new IRecentsAnimationRunner.Stub() {
+ @Override
public void onAnimationStart(IRecentsAnimationController controller,
RemoteAnimationTarget[] apps, Rect homeContentInsets,
Rect minimizedHomeBounds) {
@@ -230,8 +231,9 @@
homeContentInsets, minimizedHomeBounds);
}
- public void onAnimationCanceled() {
- animationHandler.onAnimationCanceled();
+ @Override
+ public void onAnimationCanceled(boolean deferredWithScreenshot) {
+ animationHandler.onAnimationCanceled(deferredWithScreenshot);
}
};
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index ea6fb48..7b39ba3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -78,4 +78,12 @@
}
});
}
+
+ /**
+ * Sets the flag to freeze the recents task list reordering as a part of launching the activity.
+ */
+ public static ActivityOptions setFreezeRecentTasksList(ActivityOptions opts) {
+ opts.setFreezeRecentTasksReordering();
+ return opts;
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 9bebb14..1d9105c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -84,4 +84,20 @@
Log.e(TAG, "Failed to finish recents animation", e);
}
}
+
+ public void setCancelWithDeferredScreenshot(boolean screenshot) {
+ try {
+ mAnimationController.setCancelWithDeferredScreenshot(screenshot);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set cancel with deferred screenshot", e);
+ }
+ }
+
+ public void cleanupScreenshot() {
+ try {
+ mAnimationController.cleanupScreenshot();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to clean up screenshot of recents animation", e);
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
index a473db1..5850fda 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationListener.java
@@ -29,5 +29,5 @@
/**
* Called when the animation into Recents was canceled. This call is made on the binder thread.
*/
- void onAnimationCanceled();
-}
\ No newline at end of file
+ void onAnimationCanceled(boolean deferredWithScreenshot);
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index d40fa66..ce65b5a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -60,8 +60,8 @@
*/
private ViewGroup mBigClockContainer;
/**
- * Status area (date and other stuff) shown below the clock. Plugin can decide whether
- * or not to show it below the alternate clock.
+ * Status area (date and other stuff) shown below the clock. Plugin can decide whether or not to
+ * show it below the alternate clock.
*/
private View mKeyguardStatusArea;
/**
@@ -75,24 +75,19 @@
private boolean mSupportsDarkText;
private int[] mColorPalette;
+ /**
+ * Track the state of the status bar to know when to hide the big_clock_container.
+ */
+ private int mStatusBarState;
+
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@Override
public void onStateChanged(int newState) {
- if (mBigClockContainer == null) {
- return;
- }
- if (newState == StatusBarState.SHADE) {
- if (mBigClockContainer.getVisibility() == View.VISIBLE) {
- mBigClockContainer.setVisibility(View.INVISIBLE);
- }
- } else {
- if (mBigClockContainer.getVisibility() == View.INVISIBLE) {
- mBigClockContainer.setVisibility(View.VISIBLE);
- }
- }
+ mStatusBarState = newState;
+ updateBigClockVisibility();
}
- };
+ };
private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
@@ -139,7 +134,9 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener);
- Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+ StatusBarStateController stateController = Dependency.get(StatusBarStateController.class);
+ stateController.addCallback(mStateListener);
+ mStateListener.onStateChanged(stateController.getState());
SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class);
colorExtractor.addOnColorsChangedListener(mColorsListener);
updateColors(colorExtractor);
@@ -151,7 +148,7 @@
Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener);
Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
Dependency.get(SysuiColorExtractor.class)
- .removeOnColorsChangedListener(mColorsListener);
+ .removeOnColorsChangedListener(mColorsListener);
setClockPlugin(null);
}
@@ -164,7 +161,7 @@
}
if (mBigClockContainer != null) {
mBigClockContainer.removeAllViews();
- mBigClockContainer.setVisibility(View.GONE);
+ updateBigClockVisibility();
}
mClockPlugin = null;
}
@@ -184,7 +181,7 @@
View bigClockView = plugin.getBigClockView();
if (bigClockView != null && mBigClockContainer != null) {
mBigClockContainer.addView(bigClockView);
- mBigClockContainer.setVisibility(View.VISIBLE);
+ updateBigClockVisibility();
}
// Hide default clock.
if (!plugin.shouldShowStatusArea()) {
@@ -208,12 +205,10 @@
View bigClockView = mClockPlugin.getBigClockView();
if (bigClockView != null) {
container.addView(bigClockView);
- if (container.getVisibility() == View.GONE) {
- container.setVisibility(View.VISIBLE);
- }
}
}
mBigClockContainer = container;
+ updateBigClockVisibility();
}
/**
@@ -254,6 +249,7 @@
/**
* Set the amount (ratio) that the device has transitioned to doze.
+ *
* @param darkAmount Amount of transition to doze: 1f for doze and 0f for awake.
*/
public void setDarkAmount(float darkAmount) {
@@ -307,9 +303,24 @@
}
}
+ private void updateBigClockVisibility() {
+ if (mBigClockContainer == null) {
+ return;
+ }
+ final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
+ || mStatusBarState == StatusBarState.SHADE_LOCKED;
+ final int visibility =
+ inDisplayState && mBigClockContainer.getChildCount() != 0 ? View.VISIBLE
+ : View.GONE;
+ if (mBigClockContainer.getVisibility() != visibility) {
+ mBigClockContainer.setVisibility(visibility);
+ }
+ }
+
/**
- * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock
- * in these cases.
+ * Sets if the keyguard slice is showing a center-aligned header. We need a smaller clock in
+ * these
+ * cases.
*/
public void setKeyguardShowingHeader(boolean hasHeader) {
if (mShowingHeader == hasHeader || hasCustomClock()) {
@@ -327,12 +338,12 @@
mClockView.getPaddingRight(), paddingBottom);
}
- @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
ClockManager.ClockChangedListener getClockChangedListener() {
return mClockChangedListener;
}
- @VisibleForTesting (otherwise = VisibleForTesting.NONE)
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
StatusBarStateController.StateListener getStateListener() {
return mStateListener;
}
@@ -352,7 +363,8 @@
/**
* Special layout transition that scales the clock view as its bounds change, to make it look
- * like the text is shrinking.
+ * like
+ * the text is shrinking.
*/
private class ClockBoundsTransition extends ChangeBounds {
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
index 97d7999..d631cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareBgDrawable.java
@@ -115,4 +115,4 @@
public void setRotatedBackground(boolean rotatedBackground) {
mRotatedBackground = rotatedBackground;
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 0113d05..ed2a6b5 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -19,9 +19,7 @@
import android.content.Context;
import android.graphics.Rect;
import android.opengl.GLSurfaceView;
-import android.os.Build;
import android.service.wallpaper.WallpaperService;
-import android.util.Log;
import android.view.SurfaceHolder;
import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
@@ -34,15 +32,7 @@
private static final String TAG = ImageWallpaper.class.getSimpleName();
@Override
- public void onCreate() {
- super.onCreate();
- }
-
- @Override
public Engine onCreateEngine() {
- if (Build.IS_DEBUGGABLE) {
- Log.v(TAG, "We are using GLEngine");
- }
return new GLEngine(this);
}
@@ -72,8 +62,15 @@
}
}
+ @Override
+ public void onDestroy() {
+ if (mWallpaperSurfaceView != null) {
+ mWallpaperSurfaceView.onPause();
+ }
+ }
+
private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView {
- private WallpaperStatusListener mWallpaperChangedListener;
+ private WallpaperStatusListener mWallpaperStatusListener;
GLWallpaperSurfaceView(Context context) {
super(context);
@@ -88,18 +85,18 @@
@Override
public void setRenderer(Renderer renderer) {
super.setRenderer(renderer);
- mWallpaperChangedListener = (WallpaperStatusListener) renderer;
+ mWallpaperStatusListener = (WallpaperStatusListener) renderer;
}
private void notifyAmbientModeChanged(boolean inAmbient, long duration) {
- if (mWallpaperChangedListener != null) {
- mWallpaperChangedListener.onAmbientModeChanged(inAmbient, duration);
+ if (mWallpaperStatusListener != null) {
+ mWallpaperStatusListener.onAmbientModeChanged(inAmbient, duration);
}
}
private void notifyOffsetsChanged(float xOffset, float yOffset) {
- if (mWallpaperChangedListener != null) {
- mWallpaperChangedListener.onOffsetsChanged(
+ if (mWallpaperStatusListener != null) {
+ mWallpaperStatusListener.onOffsetsChanged(
xOffset, yOffset, getHolder().getSurfaceFrame());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
index 016b8fe..4028109 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogImpl.java
@@ -191,32 +191,41 @@
mCurrentDialogArgs = args;
final int type = args.argi1;
+ // Create a new dialog but do not replace the current one yet.
+ BiometricDialogView newDialog;
if (type == BiometricAuthenticator.TYPE_FINGERPRINT) {
- mCurrentDialog = new FingerprintDialogView(mContext, mCallback);
+ newDialog = new FingerprintDialogView(mContext, mCallback);
} else if (type == BiometricAuthenticator.TYPE_FACE) {
- mCurrentDialog = new FaceDialogView(mContext, mCallback);
+ newDialog = new FaceDialogView(mContext, mCallback);
} else {
Log.e(TAG, "Unsupported type: " + type);
- }
-
- if (savedState != null) {
- mCurrentDialog.restoreState(savedState);
- }
-
- if (DEBUG) Log.d(TAG, "handleShowDialog, isAnimatingAway: "
- + mCurrentDialog.isAnimatingAway() + " type: " + type);
-
- if (mCurrentDialog.isAnimatingAway()) {
- mCurrentDialog.forceRemove();
- } else if (mDialogShowing) {
- Log.w(TAG, "Dialog already showing");
return;
}
+
+ if (DEBUG) Log.d(TAG, "handleShowDialog, "
+ + " savedState: " + savedState
+ + " mCurrentDialog: " + mCurrentDialog
+ + " newDialog: " + newDialog
+ + " type: " + type);
+
+ if (savedState != null) {
+ // SavedState is only non-null if it's from onConfigurationChanged. Restore the state
+ // even though it may be removed / re-created again
+ newDialog.restoreState(savedState);
+ } else if (mCurrentDialog != null && mDialogShowing) {
+ // If somehow we're asked to show a dialog, the old one doesn't need to be animated
+ // away. This can happen if the app cancels and re-starts auth during configuration
+ // change. This is ugly because we also have to do things on onConfigurationChanged
+ // here.
+ mCurrentDialog.forceRemove();
+ }
+
mReceiver = (IBiometricServiceReceiverInternal) args.arg2;
- mCurrentDialog.setBundle((Bundle)args.arg1);
- mCurrentDialog.setRequireConfirmation((boolean) args.arg3);
- mCurrentDialog.setUserId(args.argi2);
- mCurrentDialog.setSkipIntro(skipAnimation);
+ newDialog.setBundle((Bundle) args.arg1);
+ newDialog.setRequireConfirmation((boolean) args.arg3);
+ newDialog.setUserId(args.argi2);
+ newDialog.setSkipIntro(skipAnimation);
+ mCurrentDialog = newDialog;
mWindowManager.addView(mCurrentDialog, mCurrentDialog.getLayoutParams());
mDialogShowing = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e0ed111..4a2731e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -61,6 +61,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import java.lang.annotation.Retention;
@@ -74,7 +75,8 @@
* The controller manages addition, removal, and visible state of bubbles on screen.
*/
@Singleton
-public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener {
+public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener,
+ ConfigurationController.ConfigurationListener {
private static final String TAG = "BubbleController";
@@ -84,6 +86,7 @@
@IntDef({DISMISS_USER_GESTURE, DISMISS_AGED, DISMISS_TASK_FINISHED, DISMISS_BLOCKED,
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION})
@interface DismissReason {}
+
static final int DISMISS_USER_GESTURE = 1;
static final int DISMISS_AGED = 2;
static final int DISMISS_TASK_FINISHED = 3;
@@ -151,6 +154,7 @@
public interface BubbleExpandListener {
/**
* Called when the expansion state of the bubble stack changes.
+ *
* @param isExpanding whether it's expanding or collapsing
* @param key the notification key associated with bubble being expanded
*/
@@ -179,13 +183,16 @@
@Inject
public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
- BubbleData data) {
- this(context, statusBarWindowController, data, null /* synchronizer */);
+ BubbleData data, ConfigurationController configurationController) {
+ this(context, statusBarWindowController, data, null /* synchronizer */,
+ configurationController);
}
public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
- BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer) {
+ BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
+ ConfigurationController configurationController) {
mContext = context;
+ configurationController.addCallback(this /* configurationListener */);
mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
@@ -215,6 +222,20 @@
mSurfaceSynchronizer = synchronizer;
}
+ @Override
+ public void onUiModeChanged() {
+ if (mStackView != null) {
+ mStackView.onConfigChanged();
+ }
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ if (mStackView != null) {
+ mStackView.onConfigChanged();
+ }
+ }
+
/**
* Set a listener to be notified when some states of the bubbles change.
*/
@@ -295,7 +316,7 @@
/**
* Adds or updates a bubble associated with the provided notification entry.
*
- * @param notif the notification associated with this bubble.
+ * @param notif the notification associated with this bubble.
* @param updatePosition whether this update should promote the bubble to the top of the stack.
*/
public void updateBubble(NotificationEntry notif, boolean updatePosition) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 856b9d6..14e910f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -94,6 +94,9 @@
private boolean mActivityViewReady = false;
private PendingIntent mBubbleIntent;
+ private boolean mKeyboardVisible;
+ private boolean mNeedsNewHeight;
+
private int mMinHeight;
private int mHeaderHeight;
private int mBubbleHeight;
@@ -227,21 +230,15 @@
true /* singleTaskInstance */);
addView(mActivityView);
- mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
- ActivityView activityView = (ActivityView) view;
- // Here we assume that the position of the ActivityView on the screen
- // remains regardless of IME status. When we move ActivityView, the
- // forwardedInsets should be computed not against the current location
- // and size, but against the post-moved location and size.
- Point displaySize = new Point();
- view.getContext().getDisplay().getSize(displaySize);
- int[] windowLocation = view.getLocationOnScreen();
- final int windowBottom = windowLocation[1] + view.getHeight();
+ setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ // Keep track of IME displaying because we should not make any adjustments that might
+ // cause a config change while the IME is displayed otherwise it'll loose focus.
final int keyboardHeight = insets.getSystemWindowInsetBottom()
- insets.getStableInsetBottom();
- final int insetsBottom = Math.max(0,
- windowBottom + keyboardHeight - displaySize.y);
- activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+ mKeyboardVisible = keyboardHeight != 0;
+ if (!mKeyboardVisible && mNeedsNewHeight) {
+ updateHeight();
+ }
return view.onApplyWindowInsets(insets);
});
@@ -258,6 +255,34 @@
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mKeyboardVisible = false;
+ mNeedsNewHeight = false;
+ if (mActivityView != null) {
+ mActivityView.setForwardedInsets(Insets.of(0, 0, 0, 0));
+ }
+ }
+
+ /**
+ * Called by {@link BubbleStackView} when the insets for the expanded state should be updated.
+ * This should be done post-move and post-animation.
+ */
+ void updateInsets(WindowInsets insets) {
+ if (usingActivityView()) {
+ Point displaySize = new Point();
+ mActivityView.getContext().getDisplay().getSize(displaySize);
+ int[] windowLocation = mActivityView.getLocationOnScreen();
+ final int windowBottom = windowLocation[1] + mActivityView.getHeight();
+ final int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ final int insetsBottom = Math.max(0,
+ windowBottom + keyboardHeight - displaySize.y);
+ mActivityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+ }
+ }
+
/**
* Creates a background with corners rounded based on how the view is configured to display
*/
@@ -354,6 +379,13 @@
}
}
+ /**
+ * Update bubble expanded view header when user toggles dark mode.
+ */
+ void updateHeaderColor() {
+ mHeaderView.setBackgroundColor(mContext.getColor(R.attr.colorAccent));
+ }
+
private void updateHeaderView() {
mSettingsIcon.setContentDescription(getResources().getString(
R.string.bubbles_settings_button_description, mAppName));
@@ -378,6 +410,8 @@
mPermissionView.setVisibility(VISIBLE);
((ImageView) mPermissionView.findViewById(R.id.pkgicon)).setImageDrawable(mAppIcon);
((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName);
+ ((TextView) mPermissionView.findViewById(R.id.prompt)).setText(
+ getResources().getString(R.string.bubbles_prompt, mAppName));
logBubbleClickEvent(mEntry.notification,
StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_DIALOG_SHOWN);
}
@@ -441,9 +475,15 @@
int height = Math.min(desiredHeight, max);
height = Math.max(height, mMinHeight);
LayoutParams lp = (LayoutParams) mActivityView.getLayoutParams();
- lp.height = height;
- mBubbleHeight = height;
- mActivityView.setLayoutParams(lp);
+ mNeedsNewHeight = lp.height != height;
+ if (!mKeyboardVisible) {
+ // If the keyboard is visible... don't adjust the height because that will cause
+ // a configuration change and the keyboard will be lost.
+ lp.height = height;
+ mBubbleHeight = height;
+ mActivityView.setLayoutParams(lp);
+ mNeedsNewHeight = false;
+ }
} else {
mBubbleHeight = mNotifRow != null ? mNotifRow.getIntrinsicHeight() : mMinHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 1cc6b87..580acb8 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -128,6 +128,7 @@
private Bubble mExpandedBubble;
private boolean mIsExpanded;
+ private boolean mImeVisible;
private BubbleTouchHandler mTouchHandler;
private BubbleController.BubbleExpandListener mExpandListener;
@@ -236,6 +237,35 @@
setClipChildren(false);
setFocusable(true);
mBubbleContainer.bringToFront();
+
+ setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ final int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ if (!mIsExpanded) {
+ return view.onApplyWindowInsets(insets);
+ }
+ mImeVisible = keyboardHeight != 0;
+
+ float newY = getYPositionForExpandedView();
+ if (newY < 0) {
+ // TODO: This means our expanded content is too big to fit on screen. Right now
+ // we'll let it translate off but we should be clipping it & pushing the header
+ // down so that it always remains visible.
+ }
+ mExpandedViewYAnim.animateToFinalPosition(newY);
+ mExpandedAnimationController.updateYPosition(
+ // Update the insets after we're done translating otherwise position
+ // calculation for them won't be correct.
+ () -> mExpandedBubble.expandedView.updateInsets(insets));
+ return view.onApplyWindowInsets(insets);
+ });
+ }
+
+ /**
+ * Handle config changes.
+ */
+ public void onConfigChanged() {
+ mExpandedBubble.expandedView.updateHeaderColor();
}
@Override
@@ -639,15 +669,6 @@
}
}
- /**
- * The width of the collapsed stack of bubbles.
- */
- public int getStackWidth() {
- return mBubblePadding * (mBubbleContainer.getChildCount() - 1)
- + mBubbleSize + mBubbleContainer.getPaddingEnd()
- + mBubbleContainer.getPaddingStart();
- }
-
private void notifyExpansionChanged(NotificationEntry entry, boolean expanded) {
if (mExpandListener != null) {
mExpandListener.onBubbleExpandChanged(expanded, entry != null ? entry.key : null);
@@ -836,8 +857,13 @@
// calculation is correct)
mExpandedBubble.expandedView.updateView();
final float y = getYPositionForExpandedView();
- mExpandedViewContainer.setTranslationY(y);
- // Then update the view so that ActivityView knows we translated
+ if (!mExpandedViewYAnim.isRunning()) {
+ // We're not animating so set the value
+ mExpandedViewContainer.setTranslationY(y);
+ } else {
+ // We are animating so update the value
+ mExpandedViewYAnim.animateToFinalPosition(y);
+ }
mExpandedBubble.expandedView.updateView();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index 1f29883..40e08be 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -198,6 +198,19 @@
}
/**
+ * Animates the bubbles to {@link #getExpandedY()} position. Used in response to IME showing.
+ */
+ public void updateYPosition(Runnable after) {
+ if (mLayout == null) return;
+
+ for (int i = 0; i < mLayout.getChildCount(); i++) {
+ boolean isLast = i == mLayout.getChildCount() - 1;
+ mLayout.animateValueForChildAtIndex(DynamicAnimation.TRANSLATION_Y, i,
+ getExpandedY(), isLast ? after : null);
+ }
+ }
+
+ /**
* Animates the bubbles, starting at the given index, to the left or right by the given number
* of bubble widths. Passing zero for numBubbleWidths will animate the bubbles to their normal
* positions.
@@ -213,18 +226,25 @@
/** The Y value of the row of expanded bubbles. */
public float getExpandedY() {
- boolean showOnTop = mLayout != null
- && BubbleController.showBubblesAtTop(mLayout.getContext());
- final WindowInsets insets = mLayout != null ? mLayout.getRootWindowInsets() : null;
- if (showOnTop && insets != null) {
+ if (mLayout == null || mLayout.getRootWindowInsets() == null) {
+ return 0;
+ }
+ final boolean showOnTop = BubbleController.showBubblesAtTop(mLayout.getContext());
+ final WindowInsets insets = mLayout.getRootWindowInsets();
+ if (showOnTop) {
return mBubblePaddingPx + Math.max(
mStatusBarHeight,
insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetTop()
: 0);
} else {
- int bottomInset = insets != null ? insets.getSystemWindowInsetBottom() : 0;
- return mDisplaySize.y - mBubbleSizePx - (mPipDismissHeight - bottomInset);
+ int keyboardHeight = insets.getSystemWindowInsetBottom()
+ - insets.getStableInsetBottom();
+ float bottomInset = keyboardHeight > 0
+ ? keyboardHeight
+ : (mPipDismissHeight - insets.getStableInsetBottom());
+ // Stable insets are excluded from display size, so we must subtract it
+ return mDisplaySize.y - mBubbleSizePx - mBubblePaddingPx - bottomInset;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index d06feed..2db7306 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -61,7 +61,9 @@
@Override
public void onDestroy() {
- mPluginManager.removePluginListener(this);
+ if (mPluginManager != null) {
+ mPluginManager.removePluginListener(this);
+ }
super.onDestroy();
mDozeMachine = null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index bc3f48d..031f562 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -164,16 +164,9 @@
if (screenX != -1 && screenY != -1) {
mDozeHost.onSlpiTap(screenX, screenY);
}
- // Logs screen wake up reason of either single or double tap.
- mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
- .setType(MetricsEvent.TYPE_UPDATE).setSubtype(pulseReason));
- mMachine.wakeUp();
+ gentleWakeUp(pulseReason);
} else if (isPickup) {
- // Logs screen wake up reason of lift.
- mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
- .setType(MetricsEvent.TYPE_UPDATE)
- .setSubtype(DozeLog.REASON_SENSOR_PICKUP));
- mMachine.wakeUp();
+ gentleWakeUp(pulseReason);
} else {
mDozeHost.extendPulse();
}
@@ -190,6 +183,20 @@
}
}
+ private void gentleWakeUp(int reason) {
+ // Log screen wake up reason (lift/pickup, tap, double-tap)
+ mMetricsLogger.write(new LogMaker(MetricsEvent.DOZING)
+ .setType(MetricsEvent.TYPE_UPDATE)
+ .setSubtype(reason));
+ if (mDozeParameters.getDisplayNeedsBlanking()) {
+ // Let's prepare the display to wake-up by drawing black.
+ // This will cover the hardware wake-up sequence, where the display
+ // becomes black for a few frames.
+ mDozeHost.setAodDimmingScrim(255f);
+ }
+ mMachine.wakeUp();
+ }
+
private void onProximityFar(boolean far) {
final boolean near = !far;
final DozeMachine.State state = mMachine.getState();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index b98ce2698..f07887e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -92,8 +92,6 @@
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.ConfigurationController;
-import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.ExtensionController.Extension;
import com.android.systemui.util.EmergencyDialerConstants;
import com.android.systemui.util.leak.RotationUtils;
import com.android.systemui.volume.SystemUIInterpolators.LogAccelerateInterpolator;
@@ -161,9 +159,8 @@
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
private final ScreenshotHelper mScreenshotHelper;
private final ScreenRecordHelper mScreenRecordHelper;
-
- private final Extension<GlobalActionsPanelPlugin> mPanelExtension;
- private ActivityStarter mActivityStarter;
+ private final ActivityStarter mActivityStarter;
+ private GlobalActionsPanelPlugin mPanelPlugin;
/**
* @param context everything needs a context :(
@@ -209,10 +206,6 @@
Dependency.get(ConfigurationController.class).addCallback(this);
- mPanelExtension = Dependency.get(ExtensionController.class)
- .newExtension(GlobalActionsPanelPlugin.class)
- .withPlugin(GlobalActionsPanelPlugin.class)
- .build();
mActivityStarter = Dependency.get(ActivityStarter.class);
}
@@ -221,9 +214,11 @@
*
* @param keyguardShowing True if keyguard is showing
*/
- public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
+ public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned,
+ GlobalActionsPanelPlugin panelPlugin) {
mKeyguardShowing = keyguardShowing;
mDeviceProvisioned = isDeviceProvisioned;
+ mPanelPlugin = panelPlugin;
if (mDialog != null) {
mDialog.dismiss();
mDialog = null;
@@ -383,8 +378,7 @@
mHasLogoutButton = true;
}
} else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
- if (shouldUseSeparatedView()
- && !mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+ if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) {
mItems.add(new EmergencyDialerAction());
}
} else {
@@ -395,14 +389,14 @@
}
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
- mItems.add(getEmergencyAction());
+ mItems.add(new EmergencyAffordanceAction());
}
mAdapter = new MyAdapter();
GlobalActionsPanelPlugin.PanelViewController panelViewController =
- mPanelExtension.get() != null
- ? mPanelExtension.get().onPanelShown(
+ mPanelPlugin != null
+ ? mPanelPlugin.onPanelShown(
new GlobalActionsPanelPlugin.Callbacks() {
@Override
public void dismissGlobalActionsMenu() {
@@ -484,7 +478,59 @@
}
}
- private class EmergencyDialerAction extends SinglePressAction {
+ private abstract class EmergencyAction extends SinglePressAction {
+ EmergencyAction(int iconResId, int messageResId) {
+ super(iconResId, messageResId);
+ }
+
+ @Override
+ public boolean shouldBeSeparated() {
+ return shouldUseSeparatedView();
+ }
+
+ @Override
+ public View create(
+ Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
+ View v = super.create(context, convertView, parent, inflater);
+ int textColor;
+ if (shouldBeSeparated()) {
+ textColor = v.getResources().getColor(
+ com.android.systemui.R.color.global_actions_alert_text);
+ } else {
+ textColor = v.getResources().getColor(
+ com.android.systemui.R.color.global_actions_text);
+ }
+ TextView messageView = v.findViewById(R.id.message);
+ messageView.setTextColor(textColor);
+ ImageView icon = (ImageView) v.findViewById(R.id.icon);
+ icon.getDrawable().setTint(textColor);
+ return v;
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+ }
+
+ private class EmergencyAffordanceAction extends EmergencyAction {
+ EmergencyAffordanceAction() {
+ super(R.drawable.emergency_icon,
+ R.string.global_action_emergency);
+ }
+
+ @Override
+ public void onPress() {
+ mEmergencyAffordanceManager.performEmergencyCall();
+ }
+ }
+
+ private class EmergencyDialerAction extends EmergencyAction {
private EmergencyDialerAction() {
super(R.drawable.ic_faster_emergency,
R.string.global_action_emergency);
@@ -501,21 +547,6 @@
EmergencyDialerConstants.ENTRY_TYPE_POWER_MENU);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
-
- @Override
- public boolean showDuringKeyguard() {
- return true;
- }
-
- @Override
- public boolean showBeforeProvisioning() {
- return true;
- }
-
- @Override
- public boolean shouldBeSeparated() {
- return true;
- }
}
private final class RestartAction extends SinglePressAction implements LongPressAction {
@@ -703,32 +734,6 @@
};
}
- private Action getEmergencyAction() {
- Drawable emergencyIcon = mContext.getDrawable(R.drawable.emergency_icon);
- if (!shouldUseSeparatedView()) {
- // use un-colored legacy treatment
- emergencyIcon.setTintList(null);
- }
-
- return new SinglePressAction(R.drawable.emergency_icon,
- R.string.global_action_emergency) {
- @Override
- public void onPress() {
- mEmergencyAffordanceManager.performEmergencyCall();
- }
-
- @Override
- public boolean showDuringKeyguard() {
- return true;
- }
-
- @Override
- public boolean showBeforeProvisioning() {
- return true;
- }
- };
- }
-
private Action getAssistAction() {
return new SinglePressAction(R.drawable.ic_action_assist_focused,
R.string.global_action_assist) {
@@ -1494,12 +1499,12 @@
private final Context mContext;
private final MyAdapter mAdapter;
private MultiListLayout mGlobalActionsLayout;
- private final Drawable mBackgroundDrawable;
+ private Drawable mBackgroundDrawable;
private final ColorExtractor mColorExtractor;
private final GlobalActionsPanelPlugin.PanelViewController mPanelController;
private boolean mKeyguardShowing;
private boolean mShowing;
- private final float mScrimAlpha;
+ private float mScrimAlpha;
ActionsDialog(Context context, MyAdapter adapter,
GlobalActionsPanelPlugin.PanelViewController plugin) {
@@ -1526,49 +1531,37 @@
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
-
- initializeLayout();
-
setTitle(R.string.global_actions);
mPanelController = plugin;
- View panelView = initializePanel();
- if (panelView == null) {
- mBackgroundDrawable = new GradientDrawable(context);
- mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
- } else {
- mBackgroundDrawable = context.getDrawable(
- com.android.systemui.R.drawable.global_action_panel_scrim);
- mScrimAlpha = 1f;
- addContentView(
- panelView,
- new ViewGroup.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
- }
- window.setBackgroundDrawable(mBackgroundDrawable);
+ initializeLayout();
}
- private View initializePanel() {
- if (isPanelEnabled(mContext) && mPanelController != null) {
- View panelView = mPanelController.getPanelContent();
- if (panelView != null) {
- FrameLayout panelContainer = new FrameLayout(mContext);
- FrameLayout.LayoutParams panelParams =
- new FrameLayout.LayoutParams(
- FrameLayout.LayoutParams.MATCH_PARENT,
- FrameLayout.LayoutParams.WRAP_CONTENT);
- panelContainer.addView(panelView, panelParams);
- return panelContainer;
- }
+ private boolean initializePanel() {
+ if (!isPanelEnabled(mContext) || mPanelController == null) {
+ return false;
}
- return null;
+ View panelView = mPanelController.getPanelContent();
+ if (panelView == null) {
+ return false;
+ }
+ FrameLayout panelContainer = new FrameLayout(mContext);
+ FrameLayout.LayoutParams panelParams =
+ new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT);
+ panelContainer.addView(panelView, panelParams);
+ addContentView(
+ panelContainer,
+ new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ return true;
}
private void initializeLayout() {
setContentView(getGlobalActionsLayoutId(mContext));
- mGlobalActionsLayout = (MultiListLayout)
- findViewById(com.android.systemui.R.id.global_actions_view);
+ mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view);
mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss());
mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() {
@Override
@@ -1581,8 +1574,18 @@
});
mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter);
- mGlobalActionsLayout.setSnapToEdge(isPanelEnabled(mContext)
- && mPanelController != null);
+
+ boolean panelEnabled = initializePanel();
+ if (!panelEnabled) {
+ mBackgroundDrawable = new GradientDrawable(mContext);
+ mScrimAlpha = ScrimController.GRADIENT_SCRIM_ALPHA;
+ } else {
+ mBackgroundDrawable = mContext.getDrawable(
+ com.android.systemui.R.drawable.global_action_panel_scrim);
+ mScrimAlpha = 1f;
+ }
+ mGlobalActionsLayout.setSnapToEdge(panelEnabled);
+ getWindow().setBackgroundDrawable(mBackgroundDrawable);
}
private int getGlobalActionsLayoutId(Context context) {
@@ -1738,7 +1741,8 @@
*/
private static boolean isPanelEnabled(Context context) {
return FeatureFlagUtils.isEnabled(
- context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED); }
+ context, FeatureFlagUtils.GLOBAL_ACTIONS_PANEL_ENABLED);
+ }
/**
* Determines whether the Global Actions menu should use a separated view for emergency actions.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index 058ea60..9a0759c 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -42,11 +42,16 @@
}
private void setBackgrounds() {
+ int gridBackgroundColor = getResources().getColor(
+ com.android.systemui.R.color.global_actions_grid_background, null);
+ int separatedBackgroundColor = getResources().getColor(
+ com.android.systemui.R.color.global_actions_separated_background, null);
HardwareBgDrawable listBackground = new HardwareBgDrawable(true, true, getContext());
- HardwareBgDrawable separatedViewBackground = new HardwareBgDrawable(true, true,
- getContext());
+ HardwareBgDrawable separatedBackground = new HardwareBgDrawable(true, true, getContext());
+ listBackground.setTint(gridBackgroundColor);
+ separatedBackground.setTint(separatedBackgroundColor);
getListView().setBackground(listBackground);
- getSeparatedView().setBackground(separatedViewBackground);
+ getSeparatedView().setBackground(separatedBackground);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 19a7cea..4cf58b7 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -37,8 +37,10 @@
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions;
+import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks {
@@ -48,6 +50,7 @@
private final Context mContext;
private final KeyguardMonitor mKeyguardMonitor;
private final DeviceProvisionedController mDeviceProvisionedController;
+ private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
private GlobalActionsDialog mGlobalActions;
private boolean mDisabled;
@@ -56,6 +59,10 @@
mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
SysUiServiceProvider.getComponent(context, CommandQueue.class).addCallback(this);
+ mPanelExtension = Dependency.get(ExtensionController.class)
+ .newExtension(GlobalActionsPanelPlugin.class)
+ .withPlugin(GlobalActionsPanelPlugin.class)
+ .build();
}
@Override
@@ -74,7 +81,8 @@
mGlobalActions = new GlobalActionsDialog(mContext, manager);
}
mGlobalActions.showDialog(mKeyguardMonitor.isShowing(),
- mDeviceProvisionedController.isDeviceProvisioned());
+ mDeviceProvisionedController.isDeviceProvisioned(),
+ mPanelExtension.get());
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index a313336..21406e5 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
@@ -110,9 +110,10 @@
mTextureBuffer.position(0);
}
- void setup() {
+ void setup(Bitmap bitmap) {
setupAttributes();
setupUniforms();
+ setupTexture(bitmap);
}
private void setupAttributes() {
@@ -159,7 +160,7 @@
glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
}
- void setupTexture(Bitmap bitmap) {
+ private void setupTexture(Bitmap bitmap) {
final int[] tids = new int[1];
if (bitmap == null) {
@@ -174,7 +175,7 @@
return;
}
- // Bind a named texture to a texturing target.
+ // Bind a named texture to a target.
glBindTexture(GL_TEXTURE_2D, tids[0]);
// Load the bitmap data and copy it over into the texture object that is currently bound.
GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
@@ -195,15 +196,8 @@
glUniform1i(mUniTexture, 0);
}
- void adjustTextureCoordinates(Bitmap bitmap, int surfaceWidth, int surfaceHeight,
- float xOffset, float yOffset) {
- if (bitmap == null) {
- Log.d(TAG, "adjustTextureCoordinates: invalid bitmap");
- return;
- }
-
- int bitmapWidth = bitmap.getWidth();
- int bitmapHeight = bitmap.getHeight();
+ void adjustTextureCoordinates(int bitmapWidth, int bitmapHeight,
+ int surfaceWidth, int surfaceHeight, float xOffset, float yOffset) {
float ratioW = 1f;
float ratioH = 1f;
float rX = 0f;
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 9df6ba5..464cbe3 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -58,6 +58,10 @@
private int mWidth = 0;
private int mHeight = 0;
+ private Bitmap mBitmap;
+ private int mBitmapWidth = 0;
+ private int mBitmapHeight = 0;
+
public ImageWallpaperRenderer(Context context, ImageGLView glView) {
mWallpaperManager = context.getSystemService(WallpaperManager.class);
if (mWallpaperManager == null) {
@@ -71,8 +75,12 @@
mGLView = glView;
if (mWallpaperManager != null) {
+ mBitmap = mWallpaperManager.getBitmap();
+ mBitmapWidth = mBitmap.getWidth();
+ mBitmapHeight = mBitmap.getHeight();
// Compute per85 as transition threshold, this is an async work.
- mImageProcessHelper.startComputingPercentile85(mWallpaperManager.getBitmap());
+ mImageProcessHelper.startComputingPercentile85(mBitmap);
+ mWallpaperManager.forgetLoadedWallpaper();
}
}
@@ -81,8 +89,8 @@
glClearColor(0f, 0f, 0f, 1.0f);
mProgram.useGLProgram(
R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
- mWallpaper.setup();
- mWallpaper.setupTexture(mWallpaperManager.getBitmap());
+ mWallpaper.setup(mBitmap);
+ mBitmap = null;
}
@Override
@@ -94,8 +102,8 @@
}
mWidth = width;
mHeight = height;
- mWallpaper.adjustTextureCoordinates(mWallpaperManager.getBitmap(),
- width, height, mXOffset, mYOffset);
+ mWallpaper.adjustTextureCoordinates(
+ mBitmapWidth, mBitmapHeight, width, height, mXOffset, mYOffset);
}
@Override
@@ -132,13 +140,7 @@
@Override
public void onOffsetsChanged(float xOffset, float yOffset, Rect frame) {
- if (frame == null || mWallpaperManager == null
- || (xOffset == mXOffset && yOffset == mYOffset)) {
- return;
- }
-
- Bitmap bitmap = mWallpaperManager.getBitmap();
- if (bitmap == null) {
+ if (frame == null || (xOffset == mXOffset && yOffset == mYOffset)) {
return;
}
@@ -151,7 +153,8 @@
Log.d(TAG, "onOffsetsChanged: width=" + width + ", height=" + height
+ ", xOffset=" + mXOffset + ", yOffset=" + mYOffset);
}
- mWallpaper.adjustTextureCoordinates(bitmap, width, height, mXOffset, mYOffset);
+ mWallpaper.adjustTextureCoordinates(
+ mBitmapWidth, mBitmapHeight, width, height, mXOffset, mYOffset);
requestRender();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 0be9e25..676e594 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2031,7 +2031,6 @@
private void handleNotifyScreenTurnedOff() {
synchronized (this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOff");
- mStatusBarKeyguardViewManager.onScreenTurnedOff();
mDrawnCallback = null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index aa972e3..8e77851 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -127,12 +127,12 @@
@Override
public void onTuningChanged(String key, String newValue) {
if (ALLOW_FANCY_ANIMATION.equals(key)) {
- mAllowFancy = newValue == null || Integer.parseInt(newValue) != 0;
+ mAllowFancy = TunerService.parseIntegerSwitch(newValue, true);
if (!mAllowFancy) {
clearAnimationState();
}
} else if (MOVE_FULL_ROWS.equals(key)) {
- mFullRows = newValue == null || Integer.parseInt(newValue) != 0;
+ mFullRows = TunerService.parseIntegerSwitch(newValue, true);
} else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
mNumQuickTiles = mQuickQsPanel.getNumQuickTiles(mQs.getContext());
clearAnimationState();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 3c3dfb1..b93f8d04 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -183,7 +183,7 @@
}
private void updateViewVisibilityForTuningValue(View view, @Nullable String newValue) {
- view.setVisibility(newValue == null || Integer.parseInt(newValue) != 0 ? VISIBLE : GONE);
+ view.setVisibility(TunerService.parseIntegerSwitch(newValue, true) ? VISIBLE : GONE);
}
public void openDetails(String subPanel) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 295abcb..2f99cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -596,7 +596,8 @@
@Override
public void appTransitionCancelled(int displayId) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId).sendToTarget();
+ mHandler.obtainMessage(MSG_APP_TRANSITION_CANCELLED, displayId, 0 /* unused */)
+ .sendToTarget();
}
}
@@ -624,7 +625,8 @@
@Override
public void appTransitionFinished(int displayId) {
synchronized (mLock) {
- mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId).sendToTarget();
+ mHandler.obtainMessage(MSG_APP_TRANSITION_FINISHED, displayId, 0 /* unused */)
+ .sendToTarget();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 0a39549..2da6824 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -492,13 +492,10 @@
int currentAlpha = getImageAlpha();
ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha);
mAlphaAnimator = animator;
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- int alpha = (int) animation.getAnimatedValue();
- if (background != null) background.mutate().setAlpha(alpha);
- setImageAlpha(alpha);
- }
+ animator.addUpdateListener(animation -> {
+ int alpha1 = (int) animation.getAnimatedValue();
+ if (background != null) background.mutate().setAlpha(alpha1);
+ setImageAlpha(alpha1);
});
animator.addListener(mAlphaEndListener);
if (interpolator == null) {
@@ -520,6 +517,10 @@
}
}
+ public boolean isAnimatingAlpha() {
+ return mAlphaAnimator != null;
+ }
+
private Animator.AnimatorListener getEndListener(final Runnable runnable) {
return new AnimatorListenerAdapter() {
boolean mCancelled;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 14dc272..2bb6e3e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -32,6 +32,7 @@
import android.view.View;
import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
@@ -58,7 +59,8 @@
private final DisplayManager mDisplayManager;
/** A displayId - nav bar maps. */
- private SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
+ @VisibleForTesting
+ SparseArray<NavigationBarFragment> mNavigationBars = new SparseArray<>();
@Inject
public NavigationBarController(Context context, @Named(MAIN_HANDLER_NAME) Handler handler) {
@@ -101,7 +103,8 @@
*
* @param display the display to add navigation bar on.
*/
- private void createNavigationBar(Display display) {
+ @VisibleForTesting
+ void createNavigationBar(Display display) {
if (display == null) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index ccb8d9b..3433fa8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification
import android.animation.ObjectAnimator
+import android.content.Context
import android.util.FloatProperty
import com.android.systemui.Interpolators
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -25,12 +26,14 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
+import com.android.systemui.statusbar.phone.DozeParameters
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NotificationWakeUpCoordinator @Inject constructor(
+ private val mContext: Context,
private val mAmbientPulseManager: AmbientPulseManager,
private val mStatusBarStateController: StatusBarStateController)
: AmbientPulseManager.OnAmbientChangedListener, StatusBarStateController.StateListener {
@@ -59,10 +62,12 @@
private var mLinearVisibilityAmount = 0.0f
private var mWakingUp = false
private val mEntrySetToClearWhenFinished = mutableSetOf<NotificationEntry>()
+ private val mDozeParameters: DozeParameters;
init {
mAmbientPulseManager.addListener(this)
mStatusBarStateController.addCallback(this)
+ mDozeParameters = DozeParameters.getInstance(mContext)
}
fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -194,7 +199,7 @@
}
override fun onAmbientStateChanged(entry: NotificationEntry, isPulsing: Boolean) {
- var animate = true
+ var animate = mDozeParameters.getAlwaysOn() && !mDozeParameters.getDisplayNeedsBlanking()
if (!isPulsing) {
if (mLinearDozeAmount != 0.0f) {
if (entry.isRowDismissed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index d7baeee..9630727c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2432,7 +2432,7 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int intrinsicBefore = getIntrinsicHeight();
super.onLayout(changed, left, top, right, bottom);
- if (intrinsicBefore != getIntrinsicHeight()) {
+ if (intrinsicBefore != getIntrinsicHeight() && intrinsicBefore != 0) {
notifyHeightChanged(true /* needsAnimation */);
}
if (mMenuRow.getMenuView() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
index 2bbc53c..fdf8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideController.java
@@ -28,6 +28,7 @@
import android.view.MotionEvent;
import android.view.View;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.statusbar.CommandQueue;
@@ -48,8 +49,10 @@
private StatusBar mStatusBar;
private NavigationBarFragment mNavigationBar;
- private int mDisplayId;
- private int mSystemUiVisibility;
+ @VisibleForTesting
+ int mDisplayId;
+ @VisibleForTesting
+ int mSystemUiVisibility;
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
@@ -123,7 +126,8 @@
}
}
- private void notifySystemUiVisibilityChanged(int vis) {
+ @VisibleForTesting
+ void notifySystemUiVisibilityChanged(int vis) {
try {
if (mLastDispatchedSystemUiVisibility != vis) {
mWindowManagerService.statusBarVisibilityChanged(mDisplayId, vis);
@@ -213,11 +217,12 @@
return mask;
}
- private boolean hasNavigationBar() {
+ boolean hasNavigationBar() {
return mNavigationBar != null;
}
- private boolean hasStatusBar() {
+ @VisibleForTesting
+ boolean hasStatusBar() {
return mStatusBar != null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 410eeae..5a7df1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -303,7 +303,6 @@
case MODE_SHOW_BOUNCER:
Trace.beginSection("MODE_UNLOCK or MODE_SHOW_BOUNCER");
if (!wasDeviceInteractive) {
- mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
mPendingShowBouncer = true;
} else {
showBouncer();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 6fe23fb..847f3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -831,6 +831,15 @@
}
}
+ /**
+ * Sets the alpha of the indication areas and affordances, excluding the lock icon.
+ */
+ public void setAffordanceAlpha(float alpha) {
+ mLeftAffordanceView.setAlpha(alpha);
+ mRightAffordanceView.setAlpha(alpha);
+ mIndicationArea.setAlpha(alpha);
+ }
+
private class DefaultLeftButton implements IntentButton {
private IconState mIconState = new IconState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 7d13679..19373ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -88,6 +88,7 @@
private int mBouncerPromptReason;
private boolean mIsAnimatingAway;
private boolean mIsScrimmed;
+ private ViewGroup mLockIconContainer;
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
@@ -171,6 +172,10 @@
return isShowing() && mIsScrimmed;
}
+ public ViewGroup getLockIconContainer() {
+ return mRoot == null || mRoot.getVisibility() != View.VISIBLE ? null : mLockIconContainer;
+ }
+
/**
* This method must be called at the end of the bouncer animation when
* the translation is performed manually by the user, otherwise FalsingManager
@@ -401,6 +406,7 @@
removeView();
mHandler.removeCallbacks(mRemoveViewRunnable);
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
+ mLockIconContainer = mRoot.findViewById(R.id.lock_icon_container);
mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mCallback);
@@ -420,6 +426,7 @@
if (mRoot != null && mRoot.getParent() == mContainer) {
mContainer.removeView(mRoot);
mRoot = null;
+ mLockIconContainer = null;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
index 7a42b03..1478a07 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java
@@ -20,7 +20,6 @@
import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.SystemClock;
-import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -103,7 +102,6 @@
private void performBack() {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
- mNavigationBarView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
private boolean shouldExecuteBackOnUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
index fcf5893..4c7fdb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java
@@ -22,6 +22,7 @@
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.os.SystemClock;
import android.util.FloatProperty;
import android.util.MathUtils;
import android.view.Gravity;
@@ -31,6 +32,7 @@
import android.view.WindowManager;
import com.android.systemui.R;
+import com.android.systemui.shared.system.QuickStepContract;
public class NavigationBarEdgePanel extends View {
private static final String TAG = "NavigationBarEdgePanel";
@@ -48,6 +50,7 @@
private static final float START_POINTING_RATIO = 0.3f;
private static final float POINTEDNESS_BEFORE_SNAP_RATIO = 0.4f;
private static final int ANIM_DURATION_MS = 150;
+ private static final long HAPTIC_TIMEOUT_MS = 200;
private final Paint mPaint = new Paint();
private final Paint mProtectionPaint = new Paint();
@@ -65,6 +68,8 @@
private float mStartY;
private float mStartX;
+ private boolean mDragSlopPassed;
+ private long mLastSlopHapticTime;
private boolean mGestureDetected;
private boolean mArrowsPointLeft;
private float mGestureLength;
@@ -169,6 +174,7 @@
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN : {
+ mDragSlopPassed = false;
show(event.getX(), event.getY());
break;
}
@@ -263,6 +269,13 @@
private void handleNewSwipePoint(float x) {
float dist = MathUtils.abs(x - mStartX);
+ // Apply a haptic on drag slop passed
+ if (!mDragSlopPassed && dist > QuickStepContract.getQuickStepDragSlopPx()) {
+ mDragSlopPassed = true;
+ performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ mLastSlopHapticTime = SystemClock.uptimeMillis();
+ }
+
setDragProgress(MathUtils.constrainedMap(
0, 1.0f,
0, mGestureLength * TRACK_LENGTH_MULTIPLIER,
@@ -286,7 +299,10 @@
}
} else {
if (!mGestureDetected) {
- performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ // Prevent another haptic if it was just used
+ if (SystemClock.uptimeMillis() - mLastSlopHapticTime > HAPTIC_TIMEOUT_MS) {
+ performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ }
mGestureDetected = true;
mLegAnimator.setFloatValues(1f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 0978901..ea30451 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -159,7 +159,8 @@
private OverviewProxyService mOverviewProxyService;
- private int mDisplayId;
+ @VisibleForTesting
+ public int mDisplayId;
private boolean mIsOnDefaultDisplay;
public boolean mHomeBlockedThisTouch;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index babee53..253bdfb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -192,7 +192,6 @@
protected int mQsMinExpansionHeight;
protected int mQsMaxExpansionHeight;
private int mQsPeekHeight;
- private int mBouncerTop;
private boolean mStackScrollerOverscrolling;
private boolean mQsExpansionFromOverscroll;
private float mLastOverscroll;
@@ -325,6 +324,7 @@
private final ShadeController mShadeController =
Dependency.get(ShadeController.class);
private int mDisplayId;
+ private KeyguardBouncer mBouncer;
/**
* Cache the resource id of the theme to avoid unnecessary work in onThemeChanged.
@@ -690,11 +690,6 @@
return count;
}
- public void setBouncerTop(int bouncerTop) {
- mBouncerTop = bouncerTop;
- positionClockAndNotifications();
- }
-
private void updateClock() {
if (!mKeyguardStatusViewAnimating) {
mKeyguardStatusView.setAlpha(mClockPositionResult.clockAlpha);
@@ -1741,7 +1736,6 @@
}
updateExpandedHeight(expandedHeight);
updateHeader();
- updateUnlockIcon();
updateNotificationTranslucency();
updatePanelExpanded();
if (DEBUG) {
@@ -1834,19 +1828,6 @@
return mNotificationStackScroller.getCurrentOverScrolledPixels(true /* top */);
}
- private void updateUnlockIcon() {
- if (mBarState == StatusBarState.KEYGUARD
- || mBarState == StatusBarState.SHADE_LOCKED) {
- boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
- KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
- if (active != mUnlockIconActive && mTracking) {
- lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true, 150,
- Interpolators.FAST_OUT_LINEAR_IN, null);
- }
- mUnlockIconActive = active;
- }
- }
-
/**
* Hides the header when notifications are colliding with it.
*/
@@ -1913,7 +1894,7 @@
? 0 : KeyguardBouncer.ALPHA_EXPANSION_THRESHOLD, 1f,
0f, 1f, getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - getQsExpansionFraction());
- mKeyguardBottomArea.setAlpha(alpha);
+ mKeyguardBottomArea.setAffordanceAlpha(alpha);
mKeyguardBottomArea.setImportantForAccessibility(alpha == 0f
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO);
@@ -2061,11 +2042,6 @@
mAffordanceHelper.reset(true);
}
}
- if (!expand && (mBarState == StatusBarState.KEYGUARD
- || mBarState == StatusBarState.SHADE_LOCKED)) {
- KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
- lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
- }
}
@Override
@@ -2215,22 +2191,6 @@
return;
}
super.startUnlockHintAnimation();
- startHighlightIconAnimation(getCenterIcon());
- }
-
- /**
- * Starts the highlight (making it fully opaque) animation on an icon.
- */
- private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
- icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
- Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
- @Override
- public void run() {
- icon.setImageAlpha(icon.getRestingAlpha(),
- true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
- Interpolators.FAST_OUT_SLOW_IN, null);
- }
- });
}
@Override
@@ -2969,6 +2929,7 @@
public void onBouncerPreHideAnimation() {
setKeyguardStatusViewVisibility(mBarState, true /* keyguardFadingAway */,
false /* goingToFullShade */);
+ updateLockIcon();
}
@Override
@@ -3058,4 +3019,54 @@
public void showTransientIndication(int id) {
mKeyguardBottomArea.showTransientIndication(id);
}
+
+ /**
+ * Sets the reference to the {@link KeyguardBouncer}.
+ */
+ public void setBouncer(KeyguardBouncer bouncer) {
+ mBouncer = bouncer;
+ updateLockIcon();
+ }
+
+ public void updateLockIcon() {
+ if (mBouncer == null) {
+ return;
+ }
+
+ ViewGroup bouncerContainer = mBouncer.getLockIconContainer();
+ LockIcon lockIcon = mKeyguardBottomArea.getLockIcon();
+
+ if (mBouncer.isAnimatingAway()) {
+ if (!lockIcon.isAnimatingAlpha() && lockIcon.getAlpha() != 0) {
+ lockIcon.setImageAlpha(0, true /* animate */);
+ }
+ // Let's not re-apply the translation if the bouncer is animating, its
+ // animation also includes translation and transition would be jarring.
+ return;
+ }
+
+ float translation = 0;
+ if (bouncerContainer != null) {
+ float bottomAreaContainerY = getCommonTop(lockIcon);
+ float bouncerLockY = getCommonTop(bouncerContainer);
+ if (bouncerLockY < bottomAreaContainerY) {
+ translation = bouncerLockY - bottomAreaContainerY;
+ }
+ }
+ lockIcon.setTranslationY(translation);
+
+ if (lockIcon.getAlpha() != 1) {
+ lockIcon.setImageAlpha(1, false /* animate */);
+ }
+ }
+
+ private static float getCommonTop(View view) {
+ float y = view.getTop();
+ ViewGroup parent = (ViewGroup) view.getParent();
+ while (!(parent instanceof StatusBarWindowView)) {
+ y += parent.getY();
+ parent = (ViewGroup) parent.getParent();
+ }
+ return y;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 2495d22..99345d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -1115,6 +1115,7 @@
View[] viewsToAnimate = {
mKeyguardBottomArea.getIndicationArea(),
+ mKeyguardBottomArea.getLockIcon(),
mStatusBar.getAmbientIndicationContainer()};
for (View v : viewsToAnimate) {
if (v == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 8db0822..319a504 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -122,6 +122,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.ViewMediatorCallback;
@@ -215,7 +216,6 @@
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -533,8 +533,7 @@
private KeyguardUserSwitcher mKeyguardUserSwitcher;
protected UserSwitcherController mUserSwitcherController;
private NetworkController mNetworkController;
- private KeyguardMonitorImpl mKeyguardMonitor
- = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
+ private KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
private BatteryController mBatteryController;
protected boolean mPanelExpanded;
private UiModeManager mUiModeManager;
@@ -882,7 +881,6 @@
mNotificationPanel.getLockIcon());
mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
-
mAmbientIndicationContainer = mStatusBarWindow.findViewById(
R.id.ambient_indication_container);
@@ -1058,8 +1056,21 @@
mNotificationShelf.setOnActivatedListener(mPresenter);
mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
- mNotificationActivityStarter = new StatusBarNotificationActivityStarter(
- mContext, mNotificationPanel, mPresenter, mHeadsUpManager, mActivityLaunchAnimator);
+ final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
+ (StatusBarRemoteInputCallback) Dependency.get(
+ NotificationRemoteInputManager.Callback.class);
+ final ShadeController shadeController = Dependency.get(ShadeController.class);
+ final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
+
+ mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext,
+ mCommandQueue, mAssistManager, mNotificationPanel, mPresenter, mEntryManager,
+ mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
+ mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager,
+ mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager,
+ mLockscreenUserManager, shadeController, mKeyguardMonitor,
+ mNotificationInterruptionStateProvider, mMetricsLogger,
+ new LockPatternUtils(mContext));
+
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
mEntryManager.setRowBinder(rowBinder);
@@ -1098,7 +1109,6 @@
where.getLocationInWindow(mTmpInt2);
mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
mTmpInt2[1] + where.getHeight() / 2);
- mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
mFalsingManager.onScreenOnFromTouch();
}
}
@@ -1220,6 +1230,7 @@
mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
mLightBarController.setBiometricUnlockController(mBiometricUnlockController);
mMediaManager.setBiometricUnlockController(mBiometricUnlockController);
+ mNotificationPanel.setBouncer(mStatusBarKeyguardViewManager.getBouncer());
Dependency.get(KeyguardDismissUtil.class).setDismissHandler(this::executeWhenUnlocked);
Trace.endSection();
}
@@ -2993,7 +3004,7 @@
private void updatePanelExpansionForKeyguard() {
if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
- != BiometricUnlockController.MODE_WAKE_AND_UNLOCK) {
+ != BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
instantExpandNotificationsPanel();
} else if (mState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
instantCollapseNotificationPanel();
@@ -3551,6 +3562,9 @@
}
}
+ /**
+ * Propagation of the bouncer state, indicating that it's fully visible.
+ */
public void setBouncerShowing(boolean bouncerShowing) {
mBouncerShowing = bouncerShowing;
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
@@ -3608,10 +3622,13 @@
mWakeUpCoordinator.setWakingUp(true);
mAmbientPulseManager.releaseAllImmediately();
mVisualStabilityManager.setScreenOn(true);
- updateNotificationPanelTouchState();
updateVisibleToUser();
updateIsKeyguard();
mDozeServiceHost.stopDozing();
+ // This is intentionally below the stopDozing call above, since it avoids that we're
+ // unnecessarily animating the wakeUp transition. Animations should only be enabled
+ // once we fully woke up.
+ updateNotificationPanelTouchState();
mPulseExpansionHandler.onStartedWakingUp();
}
@@ -3724,7 +3741,6 @@
PowerManager pm = mContext.getSystemService(PowerManager.class);
pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
"com.android.systemui:CAMERA_GESTURE");
- mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
}
vibrateForCameraGesture();
if (!mStatusBarKeyguardViewManager.isShowing()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5014783..338886d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -85,6 +85,7 @@
@Override
public void onFullyShown() {
updateStates();
+ mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE");
}
@Override
@@ -166,16 +167,10 @@
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
mExpansionCallback);
- mContainer.addOnLayoutChangeListener(this::onContainerLayout);
mNotificationPanelView = notificationPanelView;
notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
}
- private void onContainerLayout(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- mNotificationPanelView.setBouncerTop(mBouncer.getTop());
- }
-
@VisibleForTesting
void onPanelExpansionChanged(float expansion, boolean tracking) {
// We don't want to translate the bounce when:
@@ -198,6 +193,7 @@
mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
}
}
+ mNotificationPanelView.updateLockIcon();
}
/**
@@ -351,14 +347,6 @@
}
}
- public void onScreenTurnedOff() {
- // TODO: remove
- }
-
- public void notifyDeviceWakeUpRequested() {
- // TODO: remove
- }
-
public void setNeedsInput(boolean needsInput) {
mStatusBarWindowController.setKeyguardNeedsInput(needsInput);
}
@@ -795,6 +783,10 @@
setDozing(isDozing);
}
+ public KeyguardBouncer getBouncer() {
+ return mBouncer;
+ }
+
private static class DismissWithActionRequest {
final OnDismissAction dismissAction;
final Runnable cancelAction;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 74c0018..7e45507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.Dependency.MAIN_HANDLER;
-import static com.android.systemui.SysUiServiceProvider.getComponent;
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
import android.app.ActivityManager;
@@ -32,9 +31,7 @@
import android.os.AsyncTask;
import android.os.Looper;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
@@ -78,27 +75,18 @@
private static final String TAG = "NotificationClickHandler";
protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private final AssistManager mAssistManager = Dependency.get(AssistManager.class);
- private final NotificationGroupManager mGroupManager =
- Dependency.get(NotificationGroupManager.class);
- private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback =
- (StatusBarRemoteInputCallback) Dependency.get(
- NotificationRemoteInputManager.Callback.class);
- private final NotificationRemoteInputManager mRemoteInputManager =
- Dependency.get(NotificationRemoteInputManager.class);
- private final NotificationLockscreenUserManager mLockscreenUserManager =
- Dependency.get(NotificationLockscreenUserManager.class);
- private final ShadeController mShadeController = Dependency.get(ShadeController.class);
- private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
- private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
- private final NotificationEntryManager mEntryManager =
- Dependency.get(NotificationEntryManager.class);
- private final StatusBarStateController mStatusBarStateController =
- Dependency.get(StatusBarStateController.class);
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
- Dependency.get(NotificationInterruptionStateProvider.class);
- private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
-
+ private final AssistManager mAssistManager;
+ private final NotificationGroupManager mGroupManager;
+ private final StatusBarRemoteInputCallback mStatusBarRemoteInputCallback;
+ private final NotificationRemoteInputManager mRemoteInputManager;
+ private final NotificationLockscreenUserManager mLockscreenUserManager;
+ private final ShadeController mShadeController;
+ private final KeyguardMonitor mKeyguardMonitor;
+ private final ActivityStarter mActivityStarter;
+ private final NotificationEntryManager mEntryManager;
+ private final StatusBarStateController mStatusBarStateController;
+ private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final MetricsLogger mMetricsLogger;
private final Context mContext;
private final NotificationPanelView mNotificationPanel;
private final NotificationPresenter mPresenter;
@@ -113,29 +101,55 @@
private boolean mIsCollapsingToShowActivityOverLockscreen;
public StatusBarNotificationActivityStarter(Context context,
+ CommandQueue commandQueue,
+ AssistManager assistManager,
NotificationPanelView panel,
NotificationPresenter presenter,
+ NotificationEntryManager entryManager,
HeadsUpManagerPhone headsUpManager,
- ActivityLaunchAnimator activityLaunchAnimator) {
+ ActivityStarter activityStarter,
+ ActivityLaunchAnimator activityLaunchAnimator,
+ IStatusBarService statusBarService,
+ StatusBarStateController statusBarStateController,
+ KeyguardManager keyguardManager,
+ IDreamManager dreamManager,
+ NotificationRemoteInputManager remoteInputManager,
+ StatusBarRemoteInputCallback remoteInputCallback,
+ NotificationGroupManager groupManager,
+ NotificationLockscreenUserManager lockscreenUserManager,
+ ShadeController shadeController,
+ KeyguardMonitor keyguardMonitor,
+ NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ MetricsLogger metricsLogger,
+ LockPatternUtils lockPatternUtils) {
mContext = context;
mNotificationPanel = panel;
mPresenter = presenter;
- mLockPatternUtils = new LockPatternUtils(context);
mHeadsUpManager = headsUpManager;
- mKeyguardManager = context.getSystemService(KeyguardManager.class);
mActivityLaunchAnimator = activityLaunchAnimator;
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- mCommandQueue = getComponent(context, CommandQueue.class);
- mDreamManager = IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE));
-
+ mBarService = statusBarService;
+ mCommandQueue = commandQueue;
+ mKeyguardManager = keyguardManager;
+ mDreamManager = dreamManager;
+ mRemoteInputManager = remoteInputManager;
+ mLockscreenUserManager = lockscreenUserManager;
+ mShadeController = shadeController;
+ mKeyguardMonitor = keyguardMonitor;
+ mActivityStarter = activityStarter;
+ mEntryManager = entryManager;
+ mStatusBarStateController = statusBarStateController;
+ mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mMetricsLogger = metricsLogger;
+ mAssistManager = assistManager;
+ mGroupManager = groupManager;
+ mLockPatternUtils = lockPatternUtils;
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
handleFullScreenIntent(entry);
}
});
+ mStatusBarRemoteInputCallback = remoteInputCallback;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 4299af7..c2c3f81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -288,7 +288,7 @@
@Override
public void onTuningChanged(String key, String newValue) {
if (CLOCK_SECONDS.equals(key)) {
- mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0;
+ mShowSeconds = TunerService.parseIntegerSwitch(newValue, false);
updateShowSeconds();
} else {
setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(newValue)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index d4049826..1e05983 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.policy;
import static android.view.Display.INVALID_DISPLAY;
+import static android.view.KeyEvent.KEYCODE_UNKNOWN;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
@@ -65,7 +66,6 @@
private int mTouchDownX;
private int mTouchDownY;
private boolean mIsVertical;
- private boolean mSupportsLongpress = true;
private AudioManager mAudioManager;
private boolean mGestureAborted;
private boolean mLongClicked;
@@ -82,7 +82,7 @@
// Just an old-fashioned ImageView
performLongClick();
mLongClicked = true;
- } else if (mSupportsLongpress) {
+ } else {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
mLongClicked = true;
@@ -101,9 +101,8 @@
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.KeyButtonView,
defStyle, 0);
- mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0);
+ mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, KEYCODE_UNKNOWN);
- mSupportsLongpress = a.getBoolean(R.styleable.KeyButtonView_keyRepeat, true);
mPlaySounds = a.getBoolean(R.styleable.KeyButtonView_playSound, true);
TypedValue value = new TypedValue();
@@ -124,7 +123,7 @@
@Override
public boolean isClickable() {
- return mCode != 0 || super.isClickable();
+ return mCode != KEYCODE_UNKNOWN || super.isClickable();
}
public void setCode(int code) {
@@ -163,9 +162,9 @@
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
- if (mCode != 0) {
+ if (mCode != KEYCODE_UNKNOWN) {
info.addAction(new AccessibilityNodeInfo.AccessibilityAction(ACTION_CLICK, null));
- if (mSupportsLongpress || isLongClickable()) {
+ if (isLongClickable()) {
info.addAction(
new AccessibilityNodeInfo.AccessibilityAction(ACTION_LONG_CLICK, null));
}
@@ -182,13 +181,13 @@
@Override
public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
- if (action == ACTION_CLICK && mCode != 0) {
+ if (action == ACTION_CLICK && mCode != KEYCODE_UNKNOWN) {
sendEvent(KeyEvent.ACTION_DOWN, 0, SystemClock.uptimeMillis());
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
playSoundEffect(SoundEffectConstants.CLICK);
return true;
- } else if (action == ACTION_LONG_CLICK && mCode != 0) {
+ } else if (action == ACTION_LONG_CLICK && mCode != KEYCODE_UNKNOWN) {
sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
@@ -197,6 +196,7 @@
return super.performAccessibilityActionInternal(action, arguments);
}
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
final boolean showSwipeUI = mOverviewProxyService.shouldShowSwipeUpUI();
final int action = ev.getAction();
@@ -218,7 +218,7 @@
// Use raw X and Y to detect gestures in case a parent changes the x and y values
mTouchDownX = (int) ev.getRawX();
mTouchDownY = (int) ev.getRawY();
- if (mCode != 0) {
+ if (mCode != KEYCODE_UNKNOWN) {
sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
} else {
// Provide the same haptic feedback that the system offers for virtual keys.
@@ -249,7 +249,7 @@
break;
case MotionEvent.ACTION_CANCEL:
setPressed(false);
- if (mCode != 0) {
+ if (mCode != KEYCODE_UNKNOWN) {
sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
}
removeCallbacks(mCheckLongPress);
@@ -269,7 +269,7 @@
// and it feels weird to sometimes get a release haptic and other times not.
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
}
- if (mCode != 0) {
+ if (mCode != KEYCODE_UNKNOWN) {
if (doIt) {
sendEvent(KeyEvent.ACTION_UP, 0);
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
@@ -299,7 +299,7 @@
sendEvent(action, flags, SystemClock.uptimeMillis());
}
- void sendEvent(int action, int flags, long when) {
+ private void sendEvent(int action, int flags, long when) {
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(mCode)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index aba2377..01498e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -29,6 +29,25 @@
long getKeyguardFadingAwayDelay();
long calculateGoingToFullShadeDelay();
+ default boolean isDeviceInteractive() {
+ return false;
+ }
+
+ default void setLaunchTransitionFadingAway(boolean b) {
+ }
+
+ default void notifyKeyguardGoingAway(boolean b) {
+ }
+
+ default void notifyKeyguardFadingAway(long delay, long fadeoutDuration) {
+ }
+
+ default void notifyKeyguardDoneFading() {
+ }
+
+ default void notifyKeyguardState(boolean showing, boolean methodSecure, boolean occluded) {
+ }
+
interface Callback {
void onKeyguardShowingChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 3deede0..c8f389e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -22,7 +22,7 @@
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings.Global;
-import android.telephony.NetworkRegistrationState;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -474,8 +474,8 @@
private MobileIconGroup getNr5GIconGroup() {
if (mServiceState == null) return null;
- int nrStatus = mServiceState.getNrStatus();
- if (nrStatus == NetworkRegistrationState.NR_STATUS_CONNECTED) {
+ int nrState = mServiceState.getNrState();
+ if (nrState == NetworkRegistrationInfo.NR_STATE_CONNECTED) {
// Check if the NR 5G is using millimeter wave and the icon is config.
if (mServiceState.getNrFrequencyRange() == ServiceState.FREQUENCY_RANGE_MMWAVE) {
if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED_MMWAVE)) {
@@ -488,11 +488,11 @@
if (mConfig.nr5GIconMap.containsKey(Config.NR_CONNECTED)) {
return mConfig.nr5GIconMap.get(Config.NR_CONNECTED);
}
- } else if (nrStatus == NetworkRegistrationState.NR_STATUS_NOT_RESTRICTED) {
+ } else if (nrState == NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED) {
if (mConfig.nr5GIconMap.containsKey(Config.NR_NOT_RESTRICTED)) {
return mConfig.nr5GIconMap.get(Config.NR_NOT_RESTRICTED);
}
- } else if (nrStatus == NetworkRegistrationState.NR_STATUS_RESTRICTED) {
+ } else if (nrState == NetworkRegistrationInfo.NR_STATE_RESTRICTED) {
if (mConfig.nr5GIconMap.containsKey(Config.NR_RESTRICTED)) {
return mConfig.nr5GIconMap.get(Config.NR_RESTRICTED);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 3bccdab..338e178 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -107,4 +107,12 @@
});
dialog.show();
}
+
+ public static boolean parseIntegerSwitch(String value, boolean defaultValue) {
+ try {
+ return value != null ? Integer.parseInt(value) != 0 : defaultValue;
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 2df9000..52b58d4 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -39,7 +39,7 @@
@Override
public void onTuningChanged(String key, String newValue) {
- setChecked(newValue != null ? Integer.parseInt(newValue) != 0 : mDefault);
+ setChecked(TunerService.parseIntegerSwitch(newValue, mDefault));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 0805677..d2f185a 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -101,28 +101,23 @@
@Override
public void onTuningChanged(String key, String newValue) {
+ boolean volumeDownToEnterSilent = mVolumePolicy.volumeDownToEnterSilent;
+ boolean volumeUpToExitSilent = mVolumePolicy.volumeUpToExitSilent;
+ boolean doNotDisturbWhenSilent = mVolumePolicy.doNotDisturbWhenSilent;
+
if (VOLUME_DOWN_SILENT.equals(key)) {
- final boolean volumeDownToEnterSilent = newValue != null
- ? Integer.parseInt(newValue) != 0
- : DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT;
- setVolumePolicy(volumeDownToEnterSilent,
- mVolumePolicy.volumeUpToExitSilent, mVolumePolicy.doNotDisturbWhenSilent,
- mVolumePolicy.vibrateToSilentDebounce);
+ volumeDownToEnterSilent =
+ TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_DOWN_TO_ENTER_SILENT);
} else if (VOLUME_UP_SILENT.equals(key)) {
- final boolean volumeUpToExitSilent = newValue != null
- ? Integer.parseInt(newValue) != 0
- : DEFAULT_VOLUME_UP_TO_EXIT_SILENT;
- setVolumePolicy(mVolumePolicy.volumeDownToEnterSilent,
- volumeUpToExitSilent, mVolumePolicy.doNotDisturbWhenSilent,
- mVolumePolicy.vibrateToSilentDebounce);
+ volumeUpToExitSilent =
+ TunerService.parseIntegerSwitch(newValue, DEFAULT_VOLUME_UP_TO_EXIT_SILENT);
} else if (VOLUME_SILENT_DO_NOT_DISTURB.equals(key)) {
- final boolean doNotDisturbWhenSilent = newValue != null
- ? Integer.parseInt(newValue) != 0
- : DEFAULT_DO_NOT_DISTURB_WHEN_SILENT;
- setVolumePolicy(mVolumePolicy.volumeDownToEnterSilent,
- mVolumePolicy.volumeUpToExitSilent, doNotDisturbWhenSilent,
- mVolumePolicy.vibrateToSilentDebounce);
+ doNotDisturbWhenSilent =
+ TunerService.parseIntegerSwitch(newValue, DEFAULT_DO_NOT_DISTURB_WHEN_SILENT);
}
+
+ setVolumePolicy(volumeDownToEnterSilent, volumeUpToExitSilent, doNotDisturbWhenSilent,
+ mVolumePolicy.vibrateToSilentDebounce);
}
private void setVolumePolicy(boolean volumeDownToEnterSilent, boolean volumeUpToExitSilent,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index b0d1106..29505a2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -101,6 +101,8 @@
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
+ // AND in the keyguard state
+ mStateListener.onStateChanged(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
// THEN the big clock container is visible and it is the parent of the
@@ -166,6 +168,8 @@
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getBigClockView()).thenReturn(pluginView);
+ // AND in the keyguard state
+ mStateListener.onStateChanged(StatusBarState.KEYGUARD);
// WHEN the plugin is connected and then disconnected
mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
@@ -245,21 +249,25 @@
}
@Test
- public void onStateChanged_InvisibleInShade() {
+ public void onStateChanged_GoneInShade() {
// GIVEN that the big clock container is visible
mBigClockContainer.setVisibility(View.VISIBLE);
mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
// WHEN transitioned to SHADE state
mStateListener.onStateChanged(StatusBarState.SHADE);
- // THEN the container is invisible.
- assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE);
+ // THEN the container is gone.
+ assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void onStateChanged_VisibleInKeyguard() {
- // GIVEN that the big clock container is invisible
- mBigClockContainer.setVisibility(View.INVISIBLE);
+ // GIVEN that the big clock container is gone
+ mBigClockContainer.setVisibility(View.GONE);
mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ // AND GIVEN that a plugin is active.
+ ClockPlugin plugin = mock(ClockPlugin.class);
+ when(plugin.getBigClockView()).thenReturn(mBigClock);
+ mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
// WHEN transitioned to KEYGUARD state
mStateListener.onStateChanged(StatusBarState.KEYGUARD);
// THEN the container is visible.
@@ -274,6 +282,8 @@
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ // AND in the keyguard state
+ mStateListener.onStateChanged(StatusBarState.KEYGUARD);
// WHEN the container is associated with the clock switch
mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
// THEN the container remains visible.
@@ -281,20 +291,6 @@
}
@Test
- public void setBigClockContainer_invisible() {
- // GIVEN that the big clock container is invisible
- mBigClockContainer.setVisibility(View.INVISIBLE);
- // AND GIVEN that a plugin is active.
- ClockPlugin plugin = mock(ClockPlugin.class);
- when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- // WHEN the container is associated with the clock switch
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
- // THEN the container remains invisible.
- assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.INVISIBLE);
- }
-
- @Test
public void setBigClockContainer_gone() {
// GIVEN that the big clock container is gone
mBigClockContainer.setVisibility(View.GONE);
@@ -302,6 +298,8 @@
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ // AND in the keyguard state
+ mStateListener.onStateChanged(StatusBarState.KEYGUARD);
// WHEN the container is associated with the clock switch
mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
// THEN the container is made visible.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 4e9d892..63b6673 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -44,6 +44,7 @@
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.StatusBarWindowController;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
import org.junit.Test;
@@ -66,6 +67,9 @@
private IActivityManager mActivityManager;
@Mock
private DozeParameters mDozeParameters;
+ @Mock
+ private ConfigurationController mConfigurationController;
+
private FrameLayout mStatusBarView;
@Captor
private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
@@ -97,6 +101,7 @@
mStatusBarView = new FrameLayout(mContext);
mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
+
// Bubbles get added to status bar window view
mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager,
mActivityManager, mDozeParameters);
@@ -115,7 +120,7 @@
mBubbleData = new BubbleData();
mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
- mBubbleData);
+ mBubbleData, mConfigurationController);
mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
mBubbleController.setExpandListener(mBubbleExpandListener);
@@ -331,8 +336,9 @@
static class TestableBubbleController extends BubbleController {
// Let's assume surfaces can be synchronized immediately.
TestableBubbleController(Context context,
- StatusBarWindowController statusBarWindowController, BubbleData data) {
- super(context, statusBarWindowController, data, Runnable::run);
+ StatusBarWindowController statusBarWindowController, BubbleData data,
+ ConfigurationController configurationController) {
+ super(context, statusBarWindowController, data, Runnable::run, configurationController);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 8941182..1ac6bef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -18,6 +18,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -136,13 +137,14 @@
@Test
public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
doReturn(true).when(mDockManagerFake).isDocked();
+ doReturn(true).when(mParameters).getDisplayNeedsBlanking();
mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
mTriggers.onSensor(DozeLog.REASON_SENSOR_DOUBLE_TAP,
false /* sensorPerformedProxCheck */, 50 /* screenX */, 50 /* screenY */,
null /* rawValues */);
+ verify(mHost).setAodDimmingScrim(eq(255));
verify(mMachine).wakeUp();
}
-
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index dd26368..c2f55e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -41,6 +41,7 @@
private CommandQueue mCommandQueue;
private Callbacks mCallbacks;
+ private static final int SECONDARY_DISPLAY = 1;
@Before
public void setup() {
@@ -68,7 +69,6 @@
verify(mCallbacks).removeIcon(eq(slot));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testDisable() {
int state1 = 14;
@@ -79,6 +79,15 @@
}
@Test
+ public void testDisableForSecondaryDisplay() {
+ int state1 = 14;
+ int state2 = 42;
+ mCommandQueue.disable(SECONDARY_DISPLAY, state1, state2);
+ waitForIdleSync();
+ verify(mCallbacks).disable(eq(SECONDARY_DISPLAY), eq(state1), eq(state2), eq(true));
+ }
+
+ @Test
public void testExpandNotifications() {
mCommandQueue.animateExpandNotificationsPanel();
waitForIdleSync();
@@ -100,7 +109,6 @@
verify(mCallbacks).animateExpandSettingsPanel(eq(panel));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testSetSystemUiVisibility() {
Rect r = new Rect();
@@ -110,7 +118,15 @@
eq(null), eq(r));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testSetSystemUiVisibilityForSecondaryDisplay() {
+ Rect r = new Rect();
+ mCommandQueue.setSystemUiVisibility(SECONDARY_DISPLAY, 1, 2, 3, 4, null, r);
+ waitForIdleSync();
+ verify(mCallbacks).setSystemUiVisibility(eq(SECONDARY_DISPLAY), eq(1), eq(2), eq(3), eq(4),
+ eq(null), eq(r));
+ }
+
@Test
public void testTopAppWindowChanged() {
mCommandQueue.topAppWindowChanged(DEFAULT_DISPLAY, true);
@@ -118,7 +134,13 @@
verify(mCallbacks).topAppWindowChanged(eq(DEFAULT_DISPLAY), eq(true));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testTopAppWindowChangedForSecondaryDisplay() {
+ mCommandQueue.topAppWindowChanged(SECONDARY_DISPLAY, true);
+ waitForIdleSync();
+ verify(mCallbacks).topAppWindowChanged(eq(SECONDARY_DISPLAY), eq(true));
+ }
+
@Test
public void testShowImeButton() {
mCommandQueue.setImeWindowStatus(DEFAULT_DISPLAY, null, 1, 2, true);
@@ -128,6 +150,14 @@
}
@Test
+ public void testShowImeButtonForSecondaryDisplay() {
+ mCommandQueue.setImeWindowStatus(SECONDARY_DISPLAY, null, 1, 2, true);
+ waitForIdleSync();
+ verify(mCallbacks).setImeWindowStatus(
+ eq(SECONDARY_DISPLAY), eq(null), eq(1), eq(2), eq(true));
+ }
+
+ @Test
public void testShowRecentApps() {
mCommandQueue.showRecentApps(true);
waitForIdleSync();
@@ -176,7 +206,6 @@
verify(mCallbacks).toggleKeyboardShortcutsMenu(eq(1));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testSetWindowState() {
mCommandQueue.setWindowState(DEFAULT_DISPLAY, 1, 2);
@@ -185,13 +214,19 @@
}
@Test
+ public void testSetWindowStateForSecondaryDisplay() {
+ mCommandQueue.setWindowState(SECONDARY_DISPLAY, 1, 2);
+ waitForIdleSync();
+ verify(mCallbacks).setWindowState(eq(SECONDARY_DISPLAY), eq(1), eq(2));
+ }
+
+ @Test
public void testScreenPinRequest() {
mCommandQueue.showScreenPinningRequest(1);
waitForIdleSync();
verify(mCallbacks).showScreenPinningRequest(eq(1));
}
- // TODO(b/117478341): add test case for multi-display
@Test
public void testAppTransitionPending() {
mCommandQueue.appTransitionPending(DEFAULT_DISPLAY);
@@ -199,7 +234,13 @@
verify(mCallbacks).appTransitionPending(eq(DEFAULT_DISPLAY), eq(false));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testAppTransitionPendingForSecondaryDisplay() {
+ mCommandQueue.appTransitionPending(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionPending(eq(SECONDARY_DISPLAY), eq(false));
+ }
+
@Test
public void testAppTransitionCancelled() {
mCommandQueue.appTransitionCancelled(DEFAULT_DISPLAY);
@@ -207,7 +248,13 @@
verify(mCallbacks).appTransitionCancelled(eq(DEFAULT_DISPLAY));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testAppTransitionCancelledForSecondaryDisplay() {
+ mCommandQueue.appTransitionCancelled(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionCancelled(eq(SECONDARY_DISPLAY));
+ }
+
@Test
public void testAppTransitionStarting() {
mCommandQueue.appTransitionStarting(DEFAULT_DISPLAY, 1, 2);
@@ -216,7 +263,14 @@
eq(DEFAULT_DISPLAY), eq(1L), eq(2L), eq(false));
}
- // TODO(b/117478341): add test case for multi-display
+ @Test
+ public void testAppTransitionStartingForSecondaryDisplay() {
+ mCommandQueue.appTransitionStarting(SECONDARY_DISPLAY, 1, 2);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionStarting(
+ eq(SECONDARY_DISPLAY), eq(1L), eq(2L), eq(false));
+ }
+
@Test
public void testAppTransitionFinished() {
mCommandQueue.appTransitionFinished(DEFAULT_DISPLAY);
@@ -225,6 +279,13 @@
}
@Test
+ public void testAppTransitionFinishedForSecondaryDisplay() {
+ mCommandQueue.appTransitionFinished(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).appTransitionFinished(eq(SECONDARY_DISPLAY));
+ }
+
+ @Test
public void testAssistDisclosure() {
mCommandQueue.showAssistDisclosure();
waitForIdleSync();
@@ -290,4 +351,25 @@
waitForIdleSync();
verify(mCallbacks).handleSystemKey(eq(1));
}
+
+ @Test
+ public void testOnDisplayReady() {
+ mCommandQueue.onDisplayReady(DEFAULT_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).onDisplayReady(eq(DEFAULT_DISPLAY));
+ }
+
+ @Test
+ public void testOnDisplayReadyForSecondaryDisplay() {
+ mCommandQueue.onDisplayReady(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).onDisplayReady(eq(SECONDARY_DISPLAY));
+ }
+
+ @Test
+ public void testOnDisplayRemoved() {
+ mCommandQueue.onDisplayRemoved(SECONDARY_DISPLAY);
+ waitForIdleSync();
+ verify(mCallbacks).onDisplayRemoved(eq(SECONDARY_DISPLAY));
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
new file mode 100644
index 0000000..34a726d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NavigationBarControllerTest.java
@@ -0,0 +1,243 @@
+/*
+ * 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.systemui.statusbar;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.NavigationBarFragment;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarControllerTest extends SysuiTestCase {
+
+ private NavigationBarController mNavigationBarController;
+ private Display mDisplay;
+ private NavigationBarFragment mDefaultNavBar;
+ private NavigationBarFragment mSecondaryNavBar;
+
+ private static final int SECONDARY_DISPLAY = 1;
+
+ @Before
+ public void setUp() {
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+ mNavigationBarController = spy(
+ new NavigationBarController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+ initializeNavigationBars();
+ }
+
+ private void initializeNavigationBars() {
+ mNavigationBarController.mNavigationBars = mock(SparseArray.class);
+ mDefaultNavBar = mock(NavigationBarFragment.class);
+ mDefaultNavBar.mDisplayId = DEFAULT_DISPLAY;
+ doReturn(mDefaultNavBar)
+ .when(mNavigationBarController.mNavigationBars).get(DEFAULT_DISPLAY);
+
+ mSecondaryNavBar = mock(NavigationBarFragment.class);
+ mSecondaryNavBar.mDisplayId = SECONDARY_DISPLAY;
+ doReturn(mSecondaryNavBar)
+ .when(mNavigationBarController.mNavigationBars).get(SECONDARY_DISPLAY);
+ }
+
+ @After
+ public void tearDown() {
+ mNavigationBarController = null;
+ mDisplay = null;
+ mDefaultNavBar = null;
+ mSecondaryNavBar = null;
+ }
+
+ @Test
+ public void testCreateNavigationBarsIncludeDefaultTrue() {
+ initializeDisplayManager();
+ doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+ mNavigationBarController.createNavigationBars(true);
+
+ verify(mNavigationBarController).createNavigationBar(any(Display.class));
+ }
+
+ @Test
+ public void testCreateNavigationBarsIncludeDefaultFalse() {
+ initializeDisplayManager();
+ doNothing().when(mNavigationBarController).createNavigationBar(any());
+
+ mNavigationBarController.createNavigationBars(false);
+
+ verify(mNavigationBarController, never()).createNavigationBar(any());
+ }
+
+ private void initializeDisplayManager() {
+ DisplayManager displayManager = mock(DisplayManager.class);
+ mDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay();
+ Display[] displays = {mDisplay};
+ when(displayManager.getDisplays()).thenReturn(displays);
+ mContext.addMockSystemService(Context.DISPLAY_SERVICE, displayManager);
+ }
+
+ // Tests if NPE occurs when call checkNavBarModes() with invalid display.
+ @Test
+ public void testCheckNavBarModesWithInvalidDisplay() {
+ mNavigationBarController.checkNavBarModes(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testCheckNavBarModesWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).checkNavBarModes();
+
+ mNavigationBarController.checkNavBarModes(DEFAULT_DISPLAY);
+
+ verify(mDefaultNavBar).checkNavBarModes();
+ }
+
+ @Test
+ public void testCheckNavBarModesWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).checkNavBarModes();
+
+ mNavigationBarController.checkNavBarModes(SECONDARY_DISPLAY);
+
+ verify(mSecondaryNavBar).checkNavBarModes();
+ }
+
+ // Tests if NPE occurs when call finishBarAnimations() with invalid display.
+ @Test
+ public void testFinishBarAnimationsWithInvalidDisplay() {
+ mNavigationBarController.finishBarAnimations(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testFinishBarAnimationsWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).finishBarAnimations();
+
+ mNavigationBarController.finishBarAnimations(DEFAULT_DISPLAY);
+
+ verify(mDefaultNavBar).finishBarAnimations();
+ }
+
+ @Test
+ public void testFinishBarAnimationsWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).finishBarAnimations();
+
+ mNavigationBarController.finishBarAnimations(SECONDARY_DISPLAY);
+
+ verify(mSecondaryNavBar).finishBarAnimations();
+ }
+
+ // Tests if NPE occurs when call touchAutoDim() with invalid display.
+ @Test
+ public void testTouchAutoDimWithInvalidDisplay() {
+ mNavigationBarController.touchAutoDim(INVALID_DISPLAY);
+ }
+
+ @Test
+ public void testTouchAutoDimWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).touchAutoDim();
+
+ mNavigationBarController.touchAutoDim(DEFAULT_DISPLAY);
+
+ verify(mDefaultNavBar).touchAutoDim();
+ }
+
+ @Test
+ public void testTouchAutoDimWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).touchAutoDim();
+
+ mNavigationBarController.touchAutoDim(SECONDARY_DISPLAY);
+
+ verify(mSecondaryNavBar).touchAutoDim();
+ }
+
+ // Tests if NPE occurs when call transitionTo() with invalid display.
+ @Test
+ public void testTransitionToWithInvalidDisplay() {
+ mNavigationBarController.transitionTo(INVALID_DISPLAY, 3, true);
+ }
+
+ @Test
+ public void testTransitionToWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).transitionTo(anyInt(), anyBoolean());
+
+ mNavigationBarController.transitionTo(DEFAULT_DISPLAY, 3, true);
+
+ verify(mDefaultNavBar).transitionTo(eq(3), eq(true));
+ }
+
+ @Test
+ public void testTransitionToWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).transitionTo(anyInt(), anyBoolean());
+
+ mNavigationBarController.transitionTo(SECONDARY_DISPLAY, 3, true);
+
+ verify(mSecondaryNavBar).transitionTo(eq(3), eq(true));
+ }
+
+ // Tests if NPE occurs when call disableAnimationsDuringHide() with invalid display.
+ @Test
+ public void testDisableAnimationsDuringHideWithInvalidDisplay() {
+ mNavigationBarController.disableAnimationsDuringHide(INVALID_DISPLAY, 500L);
+ }
+
+ @Test
+ public void testDisableAnimationsDuringHideWithDefaultDisplay() {
+ doNothing().when(mDefaultNavBar).disableAnimationsDuringHide(anyLong());
+
+ mNavigationBarController.disableAnimationsDuringHide(DEFAULT_DISPLAY, 500L);
+
+ verify(mDefaultNavBar).disableAnimationsDuringHide(eq(500L));
+ }
+
+ @Test
+ public void testDisableAnimationsDuringHideWithSecondaryDisplay() {
+ doNothing().when(mSecondaryNavBar).disableAnimationsDuringHide(anyLong());
+
+ mNavigationBarController.disableAnimationsDuringHide(SECONDARY_DISPLAY, 500L);
+
+ verify(mSecondaryNavBar).disableAnimationsDuringHide(eq(500L));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
new file mode 100644
index 0000000..1b34a75
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoHideControllerTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.graphics.Rect;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest AutoHideControllerTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class AutoHideControllerTest extends SysuiTestCase {
+
+ private AutoHideController mAutoHideController;
+
+ private static final int FULL_MASK = 0xffffffff;
+
+ @Before
+ public void setUp() {
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+ mAutoHideController =
+ spy(new AutoHideController(mContext, Dependency.get(Dependency.MAIN_HANDLER)));
+ mAutoHideController.mDisplayId = DEFAULT_DISPLAY;
+ mAutoHideController.mSystemUiVisibility = View.VISIBLE;
+ }
+
+ @After
+ public void tearDown() {
+ mAutoHideController = null;
+ }
+
+ @Test
+ public void testSetSystemUiVisibilityEarlyReturnWithDifferentDisplay() {
+ mAutoHideController.setSystemUiVisibility(1, 1, 2, 3, 4, null, new Rect());
+
+ verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+ }
+
+ @Test
+ public void testSetSystemUiVisibilityEarlyReturnWithSameVisibility() {
+ mAutoHideController
+ .setSystemUiVisibility(DEFAULT_DISPLAY, View.VISIBLE, 2, 3, 4, null, new Rect());
+
+ verify(mAutoHideController, never()).notifySystemUiVisibilityChanged(anyInt());
+ }
+
+ // Test if status bar unhide status doesn't change without status bar.
+ @Test
+ public void testSetSystemUiVisibilityWithoutStatusBar() {
+ doReturn(false).when(mAutoHideController).hasStatusBar();
+ int expectedStatus = View.STATUS_BAR_UNHIDE;
+ mAutoHideController.mSystemUiVisibility =
+ View.SYSTEM_UI_FLAG_FULLSCREEN | View.STATUS_BAR_UNHIDE;
+
+ mAutoHideController.setSystemUiVisibility(
+ DEFAULT_DISPLAY, expectedStatus, 2, 3, FULL_MASK, null, new Rect());
+
+ assertEquals("System UI visibility should not be changed",
+ expectedStatus, mAutoHideController.mSystemUiVisibility);
+ verify(mAutoHideController, times(1)).notifySystemUiVisibilityChanged(eq(expectedStatus));
+ }
+
+ @Test
+ public void testSetSystemUiVisibilityWithVisChanged() {
+ doReturn(true).when(mAutoHideController).hasStatusBar();
+ doReturn(true).when(mAutoHideController).hasNavigationBar();
+ mAutoHideController.mSystemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.STATUS_BAR_UNHIDE
+ | View.NAVIGATION_BAR_UNHIDE;
+
+ mAutoHideController.setSystemUiVisibility(
+ DEFAULT_DISPLAY, View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE,
+ 2, 3, FULL_MASK, null, new Rect());
+
+ int expectedStatus = View.VISIBLE;
+ assertEquals(expectedStatus, mAutoHideController.mSystemUiVisibility);
+ verify(mAutoHideController).notifySystemUiVisibilityChanged(eq(expectedStatus));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index db8357a..6889c57 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -71,7 +71,7 @@
mDependency.injectMockDependency(ConfigurationController.class);
mDependency.injectMockDependency(ZenModeController.class);
NotificationWakeUpCoordinator coordinator =
- new NotificationWakeUpCoordinator(
+ new NotificationWakeUpCoordinator(mContext,
new AmbientPulseManager(mContext),
new StatusBarStateControllerImpl());
PulseExpansionHandler expansionHandler = new PulseExpansionHandler(mContext, coordinator);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 1ded6c9..5f7f422 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -29,6 +29,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -75,7 +76,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.appops.AppOpsControllerImpl;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.classifier.FalsingManager;
@@ -112,7 +112,6 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import org.junit.Before;
@@ -161,7 +160,6 @@
@Mock private NotificationPresenter mNotificationPresenter;
@Mock
private NotificationEntryListener mEntryListener;
- @Mock private BubbleController mBubbleController;
@Mock
private NotificationFilter mNotificationFilter;
@Mock
@@ -192,8 +190,8 @@
mViewHierarchyManager);
mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
mDependency.injectTestDependency(NotificationListener.class, mNotificationListener);
- mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class));
- mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsControllerImpl.class));
+ mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitor.class));
+ mDependency.injectTestDependency(AppOpsController.class, mock(AppOpsController.class));
mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
mDependency.injectTestDependency(DeviceProvisionedController.class,
mDeviceProvisionedController);
@@ -722,12 +720,25 @@
public void testOnStartedWakingUp_isNotDozing() {
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
-
mStatusBar.mDozeServiceHost.startDozing();
verify(mStatusBarStateController).setIsDozing(eq(true));
+ clearInvocations(mNotificationPanelView);
mStatusBar.mWakefulnessObserver.onStartedWakingUp();
verify(mStatusBarStateController).setIsDozing(eq(false));
+ verify(mNotificationPanelView).expand(eq(false));
+ }
+
+ @Test
+ public void testOnStartedWakingUp_doesNotDismissBouncer_whenPulsing() {
+ mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+ when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
+ mStatusBar.mDozeServiceHost.startDozing();
+ clearInvocations(mNotificationPanelView);
+
+ mStatusBar.setBouncerShowing(true);
+ mStatusBar.mWakefulnessObserver.onStartedWakingUp();
+ verify(mNotificationPanelView, never()).expand(anyBoolean());
}
static class TestableStatusBar extends StatusBar {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 2baea1a..96fad21 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -7,7 +7,7 @@
import android.net.NetworkCapabilities;
import android.os.Looper;
-import android.telephony.NetworkRegistrationState;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
@@ -151,7 +151,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
ServiceState ss = Mockito.mock(ServiceState.class);
- doReturn(NetworkRegistrationState.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
doReturn(ServiceState.FREQUENCY_RANGE_HIGH).when(ss).getNrFrequencyRange();
mPhoneStateListener.onServiceStateChanged(ss);
@@ -165,7 +165,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
ServiceState ss = Mockito.mock(ServiceState.class);
- doReturn(NetworkRegistrationState.NR_STATUS_CONNECTED).when(ss).getNrStatus();
+ doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(ss).getNrState();
doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(ss).getNrFrequencyRange();
mPhoneStateListener.onServiceStateChanged(ss);
@@ -179,7 +179,7 @@
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
TelephonyManager.NETWORK_TYPE_LTE);
ServiceState ss = Mockito.mock(ServiceState.class);
- doReturn(NetworkRegistrationState.NR_STATUS_RESTRICTED).when(ss).getNrStatus();
+ doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(ss).getNrState();
mPhoneStateListener.onServiceStateChanged(mServiceState);
verifyDataIndicators(TelephonyIcons.ICON_LTE);
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index bc42863..7447331 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7117,6 +7117,27 @@
// overridden by the system.
FIELD_NOTIFICATION_IMPORTANCE_ASST = 1691;
+ // Open: Settings > Special App Access > Do not disturb control for app
+ ZEN_ACCESS_DETAIL = 1692;
+
+ // OPEN: Settings > Face > Remove face
+ // OS: Q
+ DIALOG_FACE_REMOVE = 1693;
+
+ // FIELD - Detailed reason in screen wake. One of WAKE_REASON_* in PowerManager.
+ // OS: Q
+ FIELD_SCREEN_WAKE_REASON = 1694;
+
+ // FIELD - Detailed reason in screen sleep. One of GO_TO_SLEEP_REASON_* in PowerManager.
+ // OS: Q
+ FIELD_SCREEN_SLEEP_REASON = 1695;
+
+ // UPDATE: The screen changed policy
+ // SUBTYPE: The applied policy. One of the DISPLAY_POLICY_* constants in
+ // DisplayManagerInternal.
+ // OS: Q
+ DISPLAY_POLICY = 1696;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 0d17f22..1bcc888 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1880,6 +1880,33 @@
PROBE_STATUS_FAILURE = 3;
}
+ // Codes for cellular data network type
+ enum CellularDataNetworkType {
+ // Unknown network
+ NETWORK_TYPE_UNKNOWN = 0;
+
+ // GSM network
+ NETWORK_TYPE_GSM = 1;
+
+ // CDMA network
+ NETWORK_TYPE_CDMA = 2;
+
+ // CDMA EVDO network
+ NETWORK_TYPE_EVDO_0 = 3;
+
+ // WCDMA network
+ NETWORK_TYPE_UMTS = 4;
+
+ // TDSCDMA network
+ NETWORK_TYPE_TD_SCDMA = 5;
+
+ // LTE network
+ NETWORK_TYPE_LTE = 6;
+
+ // NR network
+ NETWORK_TYPE_NR = 7;
+ }
+
// Absolute milliseconds from device boot when these stats were sampled
optional int64 time_stamp_ms = 1;
@@ -1971,6 +1998,20 @@
// Whether current entry is for the same BSSID on the same frequency compared
// to last entry
optional bool is_same_bssid_and_freq = 29;
+
+ // Cellular data network type currently in use on the device for data transmission
+ optional CellularDataNetworkType cellular_data_network_type = 30;
+
+ // Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+ // CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+ optional int32 cellular_signal_strength_dbm = 31;
+
+ // Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+ // CDMA: Ecio, EVDO: SNR, GSM: invalid */
+ optional int32 cellular_signal_strength_db = 32;
+
+ // Whether the primary registered cell of current entry is same as that of previous entry
+ optional bool is_same_registered_cell = 33;
}
message WifiUsabilityStats {
diff --git a/services/Android.bp b/services/Android.bp
index 31385ed..567efac 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -26,7 +26,6 @@
"services.contentsuggestions",
"services.coverage",
"services.devicepolicy",
- "services.ipmemorystore",
"services.midi",
"services.net",
"services.print",
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 65e31f3..1e3f20e 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -809,13 +809,9 @@
// Announce the end of the gesture recognition.
sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
+ // Don't announce the end of a the touch interaction if users didn't lift their fingers.
if (interactionEnd) {
- // Announce the end of a the touch interaction.
sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_INTERACTION_END);
- } else {
- // If gesture detection is end, but user doesn't release the finger, announce the
- // transition to exploration state.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
}
mExitGestureDetectionModeDelayed.cancel();
@@ -1151,10 +1147,7 @@
public void run() {
// Announce the end of gesture recognition.
sendAccessibilityEvent(AccessibilityEvent.TYPE_GESTURE_DETECTION_END);
- // Clearing puts is in touch exploration state with a finger already
- // down, so announce the transition to exploration state.
clear();
- sendAccessibilityEvent(AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 6597312..c1c125d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -569,6 +569,42 @@
}
}
+ // Called by Shell command
+ boolean isDefaultAugmentedServiceEnabled(@UserIdInt int userId) {
+ enforceCallingPermissionForManagement();
+
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service != null) {
+ return service.mAugmentedAutofillResolver.isDefaultServiceEnabled(userId);
+ }
+ }
+ return false;
+ }
+
+ // Called by Shell command
+ boolean setDefaultAugmentedServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ Slog.i(mTag, "setDefaultAugmentedServiceEnabled() for userId " + userId + ": " + enabled);
+ enforceCallingPermissionForManagement();
+
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service != null) {
+ final boolean changed = service.mAugmentedAutofillResolver
+ .setDefaultServiceEnabled(userId, enabled);
+ if (changed) {
+ service.updateRemoteAugmentedAutofillService();
+ return true;
+ } else {
+ if (debug) {
+ Slog.d(TAG, "setDefaultAugmentedServiceEnabled(): already " + enabled);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
private void setLoggingLevelsLocked(boolean debug, boolean verbose) {
com.android.server.autofill.Helper.sDebug = debug;
android.view.autofill.Helper.sDebug = debug;
@@ -647,6 +683,14 @@
send(receiver, value ? 1 : 0);
}
+ private void send(@NonNull IResultReceiver receiver, int value1, int value2) {
+ try {
+ receiver.send(value1, SyncResultReceiver.bundleFor(value2));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error async reporting result to client: " + e);
+ }
+ }
+
@Nullable
@VisibleForTesting
static Map<String, String[]> getWhitelistedCompatModePackages(String setting) {
@@ -967,14 +1011,20 @@
// TODO(b/113281366): add a callback method on AM to be notified when a task is finished
// so we can clean up sessions kept alive
final int taskId = mAm.getTaskIdForActivity(activityToken, false);
- final int sessionId;
+ final long result;
synchronized (mLock) {
final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
- sessionId = service.startSessionLocked(activityToken, taskId, getCallingUid(),
+ result = service.startSessionLocked(activityToken, taskId, getCallingUid(),
appCallback, autofillId, bounds, value, hasCallback, componentName,
compatMode, mAllowInstantService, flags);
}
- send(receiver, sessionId);
+ final int sessionId = (int) result;
+ final int resultFlags = (int) (result >> 32);
+ if (resultFlags != 0) {
+ send(receiver, sessionId, resultFlags);
+ } else {
+ send(receiver, sessionId);
+ }
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 9612346..720d319 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -18,6 +18,7 @@
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
+import static android.view.autofill.AutofillManager.FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY;
import static android.view.autofill.AutofillManager.NO_SESSION;
import static com.android.server.autofill.Helper.sDebug;
@@ -53,6 +54,7 @@
import android.service.autofill.FieldClassification.Match;
import android.service.autofill.FillEventHistory;
import android.service.autofill.FillEventHistory.Event;
+import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
import android.service.autofill.UserData;
@@ -156,6 +158,7 @@
/** When was {@link PruneTask} last executed? */
private long mLastPrune = 0;
+ // TODO(b/128911469): move to AutofillManagerService
/**
* Object used to set the name of the augmented autofill service.
*/
@@ -221,7 +224,7 @@
session.removeSelfLocked();
}
}
- sendStateToClients(false);
+ sendStateToClients(/* resetClient= */ false);
}
updateRemoteAugmentedAutofillService();
return enabledChanged;
@@ -278,8 +281,15 @@
}
}
+ /**
+ * Starts a new session.
+ *
+ * @return {@code long} whose right-most 32 bits represent the session id (which is always
+ * non-negative), and the left-most contains extra flags (currently either {@code 0} or
+ * {@link FillRequest#FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY}).
+ */
@GuardedBy("mLock")
- int startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid,
+ long startSessionLocked(@NonNull IBinder activityToken, int taskId, int uid,
@NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
@NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
@NonNull ComponentName componentName, boolean compatMode,
@@ -289,33 +299,48 @@
}
final String shortComponentName = componentName.toShortString();
+ boolean forAugmentedAutofillOnly = false;
if (isAutofillDisabledLocked(componentName)) {
- if (sDebug) {
- Slog.d(TAG, "startSession(" + shortComponentName
- + "): ignored because disabled by service");
- }
+ // Service disabled autofill; that means no session, unless the activity is whitelisted
+ // for augmented autofill
+ if (isWhitelistedForAugmentedAutofillLocked(componentName)) {
+ if (sDebug) {
+ Slog.d(TAG, "startSession(" + shortComponentName + "): disabled by service but "
+ + "whitelisted for augmented autofill");
+ }
+ forAugmentedAutofillOnly = true;
- final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
- .asInterface(appCallbackToken);
- try {
- client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
- /* autofillableIds= */ null);
- } catch (RemoteException e) {
- Slog.w(TAG, "Could not notify " + shortComponentName + " that it's disabled: " + e);
- }
+ } else {
+ if (sDebug) {
+ Slog.d(TAG, "startSession(" + shortComponentName + "): ignored because "
+ + "disabled by service and not whitelisted for augmented autofill");
+ }
+ final IAutoFillManagerClient client = IAutoFillManagerClient.Stub
+ .asInterface(appCallbackToken);
+ try {
+ client.setSessionFinished(AutofillManager.STATE_DISABLED_BY_SERVICE,
+ /* autofillableIds= */ null);
+ } catch (RemoteException e) {
+ Slog.w(TAG,
+ "Could not notify " + shortComponentName + " that it's disabled: " + e);
+ }
- return NO_SESSION;
+ return NO_SESSION;
+ }
}
- if (sVerbose) Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags);
+ if (sVerbose) {
+ Slog.v(TAG, "startSession(): token=" + activityToken + ", flags=" + flags
+ + ", forAugmentedAutofillOnly=" + forAugmentedAutofillOnly);
+ }
// Occasionally clean up abandoned sessions
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid,
appCallbackToken, hasCallback, componentName, compatMode,
- bindInstantServiceAllowed, flags);
+ bindInstantServiceAllowed, forAugmentedAutofillOnly, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -324,12 +349,20 @@
"id=" + newSession.id + " uid=" + uid + " a=" + shortComponentName
+ " s=" + mInfo.getServiceInfo().packageName
+ " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
- + " hc=" + hasCallback + " f=" + flags;
+ + " hc=" + hasCallback + " f=" + flags + " aa=" + forAugmentedAutofillOnly;
mMaster.logRequestLocked(historyItem);
newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
- return newSession.id;
+ if (forAugmentedAutofillOnly) {
+ // Must embed the flag in the response, at the high-end side of the long.
+ // (session is always positive, so we don't have to worry about the signal bit)
+ final long extraFlags = ((long) FLAG_SESSION_FOR_AUGMENTED_AUTOFILL_ONLY) << 32;
+ final long result = extraFlags | newSession.id;
+ return result;
+ } else {
+ return newSession.id;
+ }
}
/**
@@ -435,7 +468,7 @@
private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int taskId, int uid,
@NonNull IBinder appCallbackToken, boolean hasCallback,
@NonNull ComponentName componentName, boolean compatMode,
- boolean bindInstantServiceAllowed, int flags) {
+ boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
// use random ids so that one app cannot know that another app creates sessions
int sessionId;
int tries = 0;
@@ -446,15 +479,17 @@
return null;
}
- sessionId = sRandom.nextInt();
- } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
+ sessionId = Math.abs(sRandom.nextInt());
+ } while (sessionId == 0 || sessionId == NO_SESSION
+ || mSessions.indexOfKey(sessionId) >= 0);
assertCallerLocked(componentName, compatMode);
final Session newSession = new Session(this, mUi, getContext(), mHandler, mUserId, mLock,
sessionId, taskId, uid, activityToken, appCallbackToken, hasCallback,
mUiLatencyHistory, mWtfHistory, mInfo.getServiceInfo().getComponentName(),
- componentName, compatMode, bindInstantServiceAllowed, flags);
+ componentName, compatMode, bindInstantServiceAllowed, forAugmentedAutofillOnly,
+ flags);
mSessions.put(newSession.id, newSession);
return newSession;
@@ -634,7 +669,7 @@
remoteFillServices.valueAt(i).destroy();
}
- sendStateToClients(true);
+ sendStateToClients(/* resetclient=*/ true);
if (mClients != null) {
mClients.kill();
mClients = null;
@@ -889,8 +924,6 @@
} else {
pw.println();
mInfo.dump(prefix2, pw);
- pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
- pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
}
pw.print(prefix); pw.print("Default component: "); pw.println(getContext()
.getString(R.string.config_defaultAutofillService));
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
index c562fb1..bbe37a5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java
@@ -109,6 +109,13 @@
+ "implementation.");
pw.println(" To reset, call with just the USER_ID argument.");
pw.println("");
+ pw.println(" set default-augmented-service-enabled USER_ID [true|false]");
+ pw.println(" Enable / disable the default augmented autofill service for the user.");
+ pw.println("");
+ pw.println(" get default-augmented-service-enabled USER_ID");
+ pw.println(" Checks whether the default augmented autofill service is enabled for "
+ + "the user.");
+ pw.println("");
pw.println(" list sessions [--user USER_ID]");
pw.println(" Lists all pending sessions.");
pw.println("");
@@ -136,6 +143,8 @@
return getFullScreenMode(pw);
case "bind-instant-service-allowed":
return getBindInstantService(pw);
+ case "default-augmented-service-enabled":
+ return getDefaultAugmentedServiceEnabled(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -158,6 +167,8 @@
return setBindInstantService(pw);
case "temporary-augmented-service":
return setTemporaryAugmentedService(pw);
+ case "default-augmented-service-enabled":
+ return setDefaultAugmentedServiceEnabled(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -314,6 +325,23 @@
return 0;
}
+ private int getDefaultAugmentedServiceEnabled(PrintWriter pw) {
+ final int userId = getNextIntArgRequired();
+ final boolean enabled = mService.isDefaultAugmentedServiceEnabled(userId);
+ pw.println(enabled);
+ return 0;
+ }
+
+ private int setDefaultAugmentedServiceEnabled(PrintWriter pw) {
+ final int userId = getNextIntArgRequired();
+ final boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ final boolean changed = mService.setDefaultAugmentedServiceEnabled(userId, enabled);
+ if (!changed) {
+ pw.println("already " + enabled);
+ }
+ return 0;
+ }
+
private int requestDestroy(PrintWriter pw) {
if (!isNextArgSessions(pw)) {
return -1;
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index b715637..3d392c7 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -211,8 +211,8 @@
* Gets the {@link AutofillId} of the autofillable nodes in the {@code structure}.
*/
@NonNull
- static ArrayList<AutofillId> getAutofillableIds(@NonNull AssistStructure structure) {
- final ArrayList<AutofillId> ids = new ArrayList<>();
+ static ArraySet<AutofillId> getAutofillableIds(@NonNull AssistStructure structure) {
+ final ArraySet<AutofillId> ids = new ArraySet<>();
final int size = structure.getWindowNodeCount();
for (int i = 0; i < size; i++) {
final WindowNode node = structure.getWindowNodeAt(i);
@@ -222,7 +222,7 @@
}
private static void addAutofillableIds(@NonNull ViewNode node,
- @NonNull ArrayList<AutofillId> ids) {
+ @NonNull ArraySet<AutofillId> ids) {
if (node.getAutofillType() != View.AUTOFILL_TYPE_NONE) {
ids.add(node.getAutofillId());
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index aaba1ed..3c17ac3 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -16,6 +16,8 @@
package com.android.server.autofill;
+import static com.android.server.autofill.Helper.sDebug;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -26,6 +28,7 @@
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.augmented.AugmentedAutofillService;
@@ -142,6 +145,16 @@
scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
}
+ private void dispatchOnFillTimeout(@NonNull ICancellationSignal cancellation) {
+ mHandler.post(() -> {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.w(mTag, "Error calling cancellation signal: " + e);
+ }
+ });
+ }
+
// TODO(b/123100811): inline into PendingAutofillRequest if it doesn't have any other subclass
private abstract static class MyPendingRequest
extends PendingRequest<RemoteAugmentedAutofillService, IAugmentedAutofillService> {
@@ -161,6 +174,7 @@
private final int mTaskId;
private final long mRequestTime = SystemClock.elapsedRealtime();
private final @NonNull IFillCallback mCallback;
+ private ICancellationSignal mCancellation;
protected PendingAutofillRequest(@NonNull RemoteAugmentedAutofillService service,
int sessionId, @NonNull IAutoFillManagerClient client, int taskId,
@@ -178,11 +192,55 @@
if (!finish()) return;
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
}
+
+ @Override
+ public void onCancellable(ICancellationSignal cancellation) {
+ synchronized (mLock) {
+ final boolean cancelled;
+ synchronized (mLock) {
+ mCancellation = cancellation;
+ cancelled = isCancelledLocked();
+ }
+ if (cancelled) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(mTag, "Error requesting a cancellation", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isCompleted() {
+ return isRequestCompleted();
+ }
+
+ @Override
+ public void cancel() {
+ synchronized (mLock) {
+ final boolean cancelled = isCancelledLocked();
+ final ICancellationSignal cancellation = mCancellation;
+ if (!cancelled) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(mTag, "Error requesting a cancellation", e);
+ }
+ }
+ }
+ }
};
}
@Override
public void run() {
+ synchronized (mLock) {
+ if (isCancelledLocked()) {
+ if (sDebug) Slog.d(mTag, "run() called after canceled");
+ return;
+ }
+ }
final RemoteAugmentedAutofillService remoteService = getService();
if (remoteService == null) return;
@@ -215,8 +273,33 @@
Slog.w(TAG, "PendingAutofillRequest timed out (" + remoteService.mRequestTimeoutMs
+ "ms) for " + remoteService);
// NOTE: so far we don't need notify RemoteAugmentedAutofillServiceCallbacks
+ final ICancellationSignal cancellation;
+ synchronized (mLock) {
+ cancellation = mCancellation;
+ }
+ if (cancellation != null) {
+ remoteService.dispatchOnFillTimeout(cancellation);
+ }
finish();
}
+
+ @Override
+ public boolean cancel() {
+ if (!super.cancel()) return false;
+
+ final ICancellationSignal cancellation;
+ synchronized (mLock) {
+ cancellation = mCancellation;
+ }
+ if (cancellation != null) {
+ try {
+ cancellation.cancel();
+ } catch (RemoteException e) {
+ Slog.e(mTag, "Error cancelling a fill request", e);
+ }
+ }
+ return true;
+ }
}
public interface RemoteAugmentedAutofillServiceCallbacks
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8793341..f08bab3 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -26,6 +26,7 @@
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString;
+import static android.view.autofill.Helper.toList;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.server.autofill.Helper.getNumericValue;
@@ -137,7 +138,11 @@
private static AtomicInteger sIdCounter = new AtomicInteger();
- /** ID of the session */
+ /**
+ * ID of the session.
+ *
+ * <p>It's always a positive number, to make it easier to embed it in a long.
+ */
public final int id;
/** uid the session is for */
@@ -266,6 +271,22 @@
@GuardedBy("mLock")
private ArrayList<LogMaker> mAugmentedRequestsLogs;
+
+ /**
+ * List of autofill ids of autofillable fields present in the AssistStructure that can be used
+ * to trigger new augmented autofill requests (because the "standard" service was not interested
+ * on autofilling the app.
+ */
+ @GuardedBy("mLock")
+ private ArraySet<AutofillId> mAugmentedAutofillableIds;
+
+ /**
+ * When {@code true}, the session was created only to handle Augmented Autofill requests (i.e.,
+ * the session would not have existed otherwsie).
+ */
+ @GuardedBy("mLock")
+ private boolean mForAugmentedAutofillOnly;
+
/**
* Receiver of assist data from the app's {@link Activity}.
*/
@@ -528,11 +549,12 @@
*/
@GuardedBy("mLock")
private void requestNewFillResponseLocked(int flags) {
-
- if ((flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) {
+ if (mForAugmentedAutofillOnly || (flags & FLAG_AUGMENTED_AUTOFILL_REQUEST) != 0) {
// TODO(b/122858578): log metrics
if (sVerbose) {
- Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead");
+ Slog.v(TAG, "requestNewFillResponse(): triggering augmented autofill instead "
+ + "(mForAugmentedAutofillOnly=" + mForAugmentedAutofillOnly
+ + ", flags=" + flags + ")");
}
triggerAugmentedAutofillLocked();
return;
@@ -554,8 +576,8 @@
mRequestLogs.put(requestId, log);
if (sVerbose) {
- Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId="
- + requestId + ", flags=" + flags);
+ Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId=" + requestId
+ + ", flags=" + flags);
}
// If the focus changes very quickly before the first request is returned each focus change
@@ -588,7 +610,10 @@
@NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
@NonNull LocalLog wtfHistory, @NonNull ComponentName serviceComponentName,
@NonNull ComponentName componentName, boolean compatMode,
- boolean bindInstantServiceAllowed, int flags) {
+ boolean bindInstantServiceAllowed, boolean forAugmentedAutofillOnly, int flags) {
+ if (sessionId < 0) {
+ wtf(null, "Non-positive sessionId: %s", sessionId);
+ }
id = sessionId;
mFlags = flags;
this.taskId = taskId;
@@ -606,6 +631,7 @@
mWtfHistory = wtfHistory;
mComponentName = componentName;
mCompatMode = compatMode;
+ mForAugmentedAutofillOnly = forAugmentedAutofillOnly;
setClientLocked(client);
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
@@ -717,14 +743,6 @@
final long disableDuration = response.getDisableDuration();
if (disableDuration > 0) {
final int flags = response.getFlags();
- if (sDebug) {
- final StringBuilder message = new StringBuilder("Service disabled autofill for ")
- .append(mComponentName)
- .append(": flags=").append(flags)
- .append(", duration=");
- TimeUtils.formatDuration(disableDuration, message);
- Slog.d(TAG, message.toString());
- }
if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) {
mService.disableAutofillForActivity(mComponentName, disableDuration,
id, mCompatMode);
@@ -732,6 +750,23 @@
mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
id, mCompatMode);
}
+ // Although "standard" autofill is disabled, it might still trigger augmented autofill
+ if (triggerAugmentedAutofillLocked() != null) {
+ mForAugmentedAutofillOnly = true;
+ if (sDebug) {
+ Slog.d(TAG, "Service disabled autofill for " + mComponentName
+ + ", but session is kept for augmented autofill only");
+ }
+ return;
+ }
+ if (sDebug) {
+ final StringBuilder message = new StringBuilder("Service disabled autofill for ")
+ .append(mComponentName)
+ .append(": flags=").append(flags)
+ .append(", duration=");
+ TimeUtils.formatDuration(disableDuration, message);
+ Slog.d(TAG, message.toString());
+ }
sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE;
}
@@ -2327,12 +2362,28 @@
return;
}
+ if (mAugmentedAutofillableIds != null && mAugmentedAutofillableIds.contains(id)) {
+ // View was already reported when server could not handle a response, but it
+ // triggered augmented autofill
+
+ if (sDebug) Slog.d(TAG, "updateLocked(" + id + "): augmented-autofillable");
+
+ // Update the view states first...
+ mCurrentViewId = viewState.id;
+ viewState.setCurrentValue(value);
+
+ // ...then trigger the augmented autofill UI
+ triggerAugmentedAutofillLocked();
+ return;
+ }
+
requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags);
// Remove the UI if the ViewState has changed.
if (!Objects.equals(mCurrentViewId, viewState.id)) {
mUi.hideFillUi(this);
mCurrentViewId = viewState.id;
+ hideAugmentedAutofillLocked(viewState);
}
// If the ViewState is ready to be displayed, onReady() will be called.
@@ -2340,8 +2391,9 @@
break;
case ACTION_VIEW_EXITED:
if (Objects.equals(mCurrentViewId, viewState.id)) {
- if (sVerbose) Slog.d(TAG, "Exiting view " + id);
+ if (sVerbose) Slog.v(TAG, "Exiting view " + id);
mUi.hideFillUi(this);
+ hideAugmentedAutofillLocked(viewState);
mCurrentViewId = null;
}
break;
@@ -2350,6 +2402,15 @@
}
}
+ @GuardedBy("mLock")
+ private void hideAugmentedAutofillLocked(@NonNull ViewState viewState) {
+ if ((viewState.getState()
+ & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
+ viewState.resetState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
+ cancelAugmentedAutofillLocked();
+ }
+ }
+
/**
* Checks whether a view should be ignored.
*/
@@ -2430,14 +2491,14 @@
}
private void notifyUnavailableToClient(int sessionFinishedState,
- @Nullable ArrayList<AutofillId> autofillableIds) {
+ @Nullable ArraySet<AutofillId> autofillableIds) {
synchronized (mLock) {
if (mCurrentViewId == null) return;
try {
if (mHasCallback) {
mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinishedState);
} else if (sessionFinishedState != 0) {
- mClient.setSessionFinished(sessionFinishedState, autofillableIds);
+ mClient.setSessionFinished(sessionFinishedState, toList(autofillableIds));
}
} catch (RemoteException e) {
Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
@@ -2560,7 +2621,7 @@
final FillContext context = getFillContextByRequestIdLocked(requestId);
- final ArrayList<AutofillId> autofillableIds;
+ final ArraySet<AutofillId> autofillableIds;
if (context != null) {
final AssistStructure structure = context.getStructure();
autofillableIds = Helper.getAutofillableIds(structure);
@@ -2583,16 +2644,12 @@
notifyUnavailableToClient(AutofillManager.STATE_FINISHED, autofillableIds);
removeSelf();
} else {
- // TODO(b/123099468, b/119638958): must set internal state so when user focus other
- // fields it does not generate a new call to the standard autofill service (right now
- // it does). In other words, must also pass the autofillableIds - we'll be handled in
- // a separate change (with new CTS tests to exercise this scenario).
-
if (sVerbose) {
Slog.v(TAG, "keeping session " + id + " when server returned null but "
+ "there is an AugmentedAutofill for user. AutofillableIds: "
+ autofillableIds);
}
+ mAugmentedAutofillableIds = autofillableIds;
}
}
@@ -2660,7 +2717,9 @@
return null;
}
- final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
+ final ViewState viewState = mViewStates.get(mCurrentViewId);
+ viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
+ final AutofillValue currentValue = viewState.getCurrentValue();
// TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
// further AFM -> AFMS calls.
@@ -2682,6 +2741,18 @@
}
@GuardedBy("mLock")
+ private void cancelAugmentedAutofillLocked() {
+ final RemoteAugmentedAutofillService remoteService = mService
+ .getRemoteAugmentedAutofillServiceLocked();
+ if (remoteService == null) {
+ Slog.w(TAG, "cancelAugmentedAutofillLocked(): no service for user");
+ return;
+ }
+ if (sVerbose) Slog.v(TAG, "cancelAugmentedAutofillLocked() on " + mCurrentViewId);
+ remoteService.onDestroyAutofillWindowsRequest();
+ }
+
+ @GuardedBy("mLock")
private void processResponseLocked(@NonNull FillResponse newResponse,
@Nullable Bundle newClientState, int flags) {
// Make sure we are hiding the UI which will be shown
@@ -2959,6 +3030,9 @@
pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
mSaveOnAllViewsInvisible);
pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
+ if (mForAugmentedAutofillOnly) {
+ pw.print(prefix); pw.println("For Augmented Autofill Only");
+ }
if (mAugmentedAutofillDestroyer != null) {
pw.print(prefix); pw.println("has mAugmentedAutofillDestroyer");
}
@@ -2967,6 +3041,10 @@
pw.println(mAugmentedRequestsLogs.size());
}
+ if (mAugmentedAutofillableIds != null) {
+ pw.print(prefix); pw.print("mAugmentedAutofillableIds: ");
+ pw.println(mAugmentedAutofillableIds);
+ }
mRemoteFillService.dump(prefix, pw);
}
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 2cc6d20..33a2e50 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -17,6 +17,7 @@
package com.android.server.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+
import static com.android.server.autofill.Helper.sDebug;
import android.annotation.NonNull;
@@ -47,8 +48,6 @@
private static final String TAG = "ViewState";
- // NOTE: state constants must be public because of flagstoString().
- public static final int STATE_UNKNOWN = 0x000;
/** Initial state. */
public static final int STATE_INITIAL = 0x001;
/** View id is present in a dataset returned by the service. */
@@ -73,6 +72,8 @@
public static final int STATE_AUTOFILL_FAILED = 0x400;
/** View has been autofilled at least once. */
public static final int STATE_AUTOFILLED_ONCE = 0x800;
+ /** View triggered the latest augmented autofill request. */
+ public static final int STATE_TRIGGERED_AUGMENTED_AUTOFILL = 0x1000;
public final AutofillId id;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index ffda581..7106664 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -362,8 +362,8 @@
* @param dataManagementIntent An {@link Intent} that can be passed to {@link
* Context#startActivity} in order to launch the transport's data-management UI. It may be
* {@code null} if the transport does not offer any user-facing data management UI.
- * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
- * management affordance. This MUST be {@code null} when dataManagementIntent is {@code
+ * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+ * data management affordance. This MUST be {@code null} when dataManagementIntent is {@code
* null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
@@ -375,7 +375,7 @@
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
- String dataManagementLabel) {
+ CharSequence dataManagementLabel) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "updateTransportAttributes()");
@@ -521,7 +521,7 @@
* transport.
*/
@Nullable
- public String getDataManagementLabel(@UserIdInt int userId, String transportName) {
+ public CharSequence getDataManagementLabel(@UserIdInt int userId, String transportName) {
UserBackupManagerService userBackupManagerService =
getServiceForUserIfCallerHasPermission(userId, "getDataManagementLabel()");
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 00cb6d3..8f0c5d8 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -630,8 +630,7 @@
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
- String dataManagementLabel) {
-
+ CharSequence dataManagementLabel) {
if (isUserReadyForBackup(userId)) {
mService.updateTransportAttributes(
userId,
@@ -710,19 +709,13 @@
}
@Override
- public String getDataManagementLabelForUser(int userId, String transport)
+ public CharSequence getDataManagementLabelForUser(int userId, String transport)
throws RemoteException {
return isUserReadyForBackup(userId) ? mService.getDataManagementLabel(userId, transport)
: null;
}
@Override
- public String getDataManagementLabel(String transport)
- throws RemoteException {
- return getDataManagementLabelForUser(binderGetCallingUserId(), transport);
- }
-
- @Override
public IRestoreSession beginRestoreSessionForUser(
int userId, String packageName, String transportID) throws RemoteException {
return isUserReadyForBackup(userId) ? mService.beginRestoreSession(userId, packageName,
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index a7bada0..30ce4cf 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -284,7 +284,7 @@
* @throws TransportNotRegisteredException if the transport is not registered.
*/
@Nullable
- public String getTransportDataManagementLabel(String transportName)
+ public CharSequence getTransportDataManagementLabel(String transportName)
throws TransportNotRegisteredException {
synchronized (mTransportLock) {
return getRegisteredTransportDescriptionOrThrowLocked(transportName)
@@ -327,7 +327,7 @@
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
- @Nullable String dataManagementLabel) {
+ @Nullable CharSequence dataManagementLabel) {
synchronized (mTransportLock) {
TransportDescription description =
mRegisteredTransportsDescriptionMap.get(transportComponent);
@@ -678,7 +678,7 @@
transport.configurationIntent(),
transport.currentDestinationString(),
transport.dataManagementIntent(),
- transport.dataManagementLabel());
+ transport.dataManagementIntentLabel());
synchronized (mTransportLock) {
mRegisteredTransportsDescriptionMap.put(transportComponent, description);
}
@@ -707,7 +707,7 @@
@Nullable private Intent configurationIntent;
private String currentDestinationString;
@Nullable private Intent dataManagementIntent;
- @Nullable private String dataManagementLabel;
+ @Nullable private CharSequence dataManagementLabel;
private TransportDescription(
String name,
@@ -715,7 +715,7 @@
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
- @Nullable String dataManagementLabel) {
+ @Nullable CharSequence dataManagementLabel) {
this.name = name;
this.transportDirName = transportDirName;
this.configurationIntent = configurationIntent;
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 32e2cac..447bd8c 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2929,8 +2929,8 @@
* {@link Context#startActivity} in order to launch the transport's data-management UI. It
* may be {@code null} if the transport does not offer any user-facing data
* management UI.
- * @param dataManagementLabel A {@link String} to be used as the label for the transport's data
- * management affordance. This MUST be {@code null} when dataManagementIntent is
+ * @param dataManagementLabel A {@link CharSequence} to be used as the label for the transport's
+ * data management affordance. This MUST be {@code null} when dataManagementIntent is
* {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
* @throws SecurityException If the UID of the calling process differs from the package UID of
* {@code transportComponent} or if the caller does NOT have BACKUP permission.
@@ -2941,7 +2941,7 @@
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
- @Nullable String dataManagementLabel) {
+ @Nullable CharSequence dataManagementLabel) {
updateTransportAttributes(
Binder.getCallingUid(),
transportComponent,
@@ -2960,7 +2960,7 @@
@Nullable Intent configurationIntent,
String currentDestinationString,
@Nullable Intent dataManagementIntent,
- @Nullable String dataManagementLabel) {
+ @Nullable CharSequence dataManagementLabel) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "updateTransportAttributes");
@@ -3159,12 +3159,12 @@
* Supply the menu label for affordances that fire the manage-data intent for the given
* transport.
*/
- public String getDataManagementLabel(String transportName) {
+ public CharSequence getDataManagementLabel(String transportName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"getDataManagementLabel");
try {
- String label = mTransportManager.getTransportDataManagementLabel(transportName);
+ CharSequence label = mTransportManager.getTransportDataManagementLabel(transportName);
if (MORE_DEBUG) {
Slog.d(TAG, "getDataManagementLabel() returning " + label);
}
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index 5125b0d..c9a6b60 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -105,7 +105,7 @@
/**
* Caller specifies whether is considered a system-level restore.
*/
- public static RestoreParams createForRestoreSome(
+ public static RestoreParams createForRestorePackages(
TransportClient transportClient,
IRestoreObserver observer,
IBackupManagerMonitor monitor,
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 0fa0f89..10304c3 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -22,6 +22,7 @@
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_GET_RESTORE_SETS;
import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.backup.IBackupManagerMonitor;
import android.app.backup.IRestoreObserver;
@@ -192,18 +193,22 @@
}
// Restores of more than a single package are treated as 'system' restores
- public synchronized int restoreSome(long token, IRestoreObserver observer,
- IBackupManagerMonitor monitor, String[] packages) {
+ public synchronized int restorePackages(long token, @Nullable IRestoreObserver observer,
+ @NonNull String[] packages, @Nullable IBackupManagerMonitor monitor) {
mBackupManagerService.getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP,
"performRestore");
if (DEBUG) {
StringBuilder b = new StringBuilder(128);
- b.append("restoreSome token=");
+ b.append("restorePackages token=");
b.append(Long.toHexString(token));
b.append(" observer=");
- b.append(observer.toString());
+ if (observer == null) {
+ b.append("null");
+ } else {
+ b.append(observer.toString());
+ }
b.append(" monitor=");
if (monitor == null) {
b.append("null");
@@ -260,7 +265,7 @@
try {
return sendRestoreToHandlerLocked(
(transportClient, listener) ->
- RestoreParams.createForRestoreSome(
+ RestoreParams.createForRestorePackages(
transportClient,
observer,
monitor,
@@ -268,7 +273,7 @@
packages,
/* isSystemRestore */ packages.length > 1,
listener),
- "RestoreSession.restoreSome(" + packages.length + " packages)");
+ "RestoreSession.restorePackages(" + packages.length + " packages)");
} finally {
Binder.restoreCallingIdentity(oldId);
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
index 86ad52d..fc9754a 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
@@ -114,7 +114,7 @@
case "temporary-service":
return setTemporaryService(pw);
case "default-service-enabled":
- return setDefaultServiceEnabled();
+ return setDefaultServiceEnabled(pw);
default:
pw.println("Invalid set: " + what);
return -1;
@@ -159,10 +159,13 @@
return 0;
}
- private int setDefaultServiceEnabled() {
+ private int setDefaultServiceEnabled(PrintWriter pw) {
final int userId = getNextIntArgRequired();
- final boolean enabled = Boolean.parseBoolean(getNextArg());
- mService.setDefaultServiceEnabled(userId, enabled);
+ final boolean enabled = Boolean.parseBoolean(getNextArgRequired());
+ final boolean changed = mService.setDefaultServiceEnabled(userId, enabled);
+ if (!changed) {
+ pw.println("already " + enabled);
+ }
return 0;
}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index c423f9c..d7d97b3 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -27,12 +27,10 @@
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_DATA;
import static com.android.server.wm.ActivityTaskManagerInternal.ASSIST_KEY_STRUCTURE;
-import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
-import android.app.AppGlobals;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.content.ComponentName;
@@ -44,12 +42,12 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.contentcapture.ActivityEvent;
import android.service.contentcapture.ActivityEvent.ActivityEventType;
import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.ContentCaptureServiceInfo;
import android.service.contentcapture.IContentCaptureServiceCallback;
import android.service.contentcapture.SnapshotData;
import android.util.ArrayMap;
@@ -107,6 +105,9 @@
@GuardedBy("mLock")
private boolean mZombie;
+ @GuardedBy("mLock")
+ private ContentCaptureServiceInfo mInfo;
+
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@@ -144,33 +145,9 @@
@Override // from PerUserSystemService
protected ServiceInfo newServiceInfoLocked(@NonNull ComponentName serviceComponent)
throws NameNotFoundException {
-
- int flags = PackageManager.GET_META_DATA;
- final boolean isTemp = isTemporaryServiceSetLocked();
- if (!isTemp) {
- flags |= PackageManager.MATCH_SYSTEM_ONLY;
- }
-
- ServiceInfo si;
- try {
- si = AppGlobals.getPackageManager().getServiceInfo(serviceComponent, flags, mUserId);
- } catch (RemoteException e) {
- Slog.w(TAG, "Could not get service for " + serviceComponent + ": " + e);
- return null;
- }
- if (si == null) {
- Slog.w(TAG, "Could not get serviceInfo for " + (isTemp ? " (temp)" : "(default system)")
- + " " + serviceComponent.flattenToShortString());
- return null;
- }
- if (!Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE.equals(si.permission)) {
- Slog.w(TAG, "ContentCaptureService from '" + si.packageName
- + "' does not require permission "
- + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
- throw new SecurityException("Service does not require permission "
- + Manifest.permission.BIND_CONTENT_CAPTURE_SERVICE);
- }
- return si;
+ mInfo = new ContentCaptureServiceInfo(getContext(), serviceComponent,
+ isTemporaryServiceSetLocked(), mUserId);
+ return mInfo.getServiceInfo();
}
@Override // from PerUserSystemService
@@ -490,9 +467,16 @@
protected void dumpLocked(String prefix, PrintWriter pw) {
super.dumpLocked(prefix, pw);
+ final String prefix2 = prefix + " ";
+ pw.print(prefix); pw.print("Service Info: ");
+ if (mInfo == null) {
+ pw.println("N/A");
+ } else {
+ pw.println();
+ mInfo.dump(prefix2, pw);
+ }
pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie);
- final String prefix2 = prefix + " ";
if (mRemoteService != null) {
pw.print(prefix); pw.println("remote service:");
mRemoteService.dump(prefix2, pw);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a400cc3..3d918fc 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -83,6 +83,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.StatsLog;
import android.util.TimeUtils;
@@ -195,6 +196,7 @@
private final Injector mInjector;
int mBroadcastRefCount = 0;
PowerManager.WakeLock mWakeLock;
+ SparseIntArray mAlarmsPerUid = new SparseIntArray();
ArrayList<Alarm> mPendingNonWakeupAlarms = new ArrayList<>();
ArrayList<InFlight> mInFlight = new ArrayList<>();
private final ArrayList<AlarmManagerInternal.InFlightListener> mInFlightListeners =
@@ -393,6 +395,8 @@
@VisibleForTesting
static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
@VisibleForTesting
+ static final String KEY_MAX_ALARMS_PER_UID = "max_alarms_per_uid";
+ @VisibleForTesting
static final String KEY_APP_STANDBY_QUOTAS_ENABLED = "app_standby_quotas_enabled";
private static final String KEY_APP_STANDBY_WINDOW = "app_standby_window";
@VisibleForTesting
@@ -420,6 +424,7 @@
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
+ private static final int DEFAULT_MAX_ALARMS_PER_UID = 500;
private static final boolean DEFAULT_APP_STANDBY_QUOTAS_ENABLED = true;
private static final long DEFAULT_APP_STANDBY_WINDOW = 60 * 60 * 1000; // 1 hr
/**
@@ -461,6 +466,8 @@
// Direct alarm listener callback timeout
public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
+ public int MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+
public boolean APP_STANDBY_QUOTAS_ENABLED = DEFAULT_APP_STANDBY_QUOTAS_ENABLED;
public long APP_STANDBY_WINDOW = DEFAULT_APP_STANDBY_WINDOW;
@@ -549,6 +556,15 @@
APP_STANDBY_QUOTAS[i] = mParser.getInt(KEYS_APP_STANDBY_QUOTAS[i],
Math.min(APP_STANDBY_QUOTAS[i - 1], DEFAULT_APP_STANDBY_QUOTAS[i]));
}
+
+ MAX_ALARMS_PER_UID = mParser.getInt(KEY_MAX_ALARMS_PER_UID,
+ DEFAULT_MAX_ALARMS_PER_UID);
+ if (MAX_ALARMS_PER_UID < DEFAULT_MAX_ALARMS_PER_UID) {
+ Slog.w(TAG, "Cannot set " + KEY_MAX_ALARMS_PER_UID + " lower than "
+ + DEFAULT_MAX_ALARMS_PER_UID);
+ MAX_ALARMS_PER_UID = DEFAULT_MAX_ALARMS_PER_UID;
+ }
+
updateAllowWhileIdleWhitelistDurationLocked();
}
}
@@ -590,6 +606,9 @@
TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw);
pw.println();
+ pw.print(KEY_MAX_ALARMS_PER_UID); pw.print("=");
+ pw.println(MAX_ALARMS_PER_UID);
+
for (int i = 0; i < KEYS_APP_STANDBY_DELAY.length; i++) {
pw.print(KEYS_APP_STANDBY_DELAY[i]); pw.print("=");
TimeUtils.formatDuration(APP_STANDBY_MIN_DELAYS[i], pw);
@@ -671,12 +690,6 @@
final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
- Batch() {
- start = 0;
- end = Long.MAX_VALUE;
- flags = 0;
- }
-
Batch(Alarm seed) {
start = seed.whenElapsed;
end = clampPositive(seed.maxWhenElapsed);
@@ -728,11 +741,16 @@
return newStart;
}
+ /**
+ * Remove an alarm from this batch.
+ * <p> <b> Should be used only while re-ordering the alarm within the service </b> as it
+ * does not update {@link #mAlarmsPerUid}
+ */
boolean remove(Alarm alarm) {
- return remove(a -> (a == alarm));
+ return remove(a -> (a == alarm), true);
}
- boolean remove(Predicate<Alarm> predicate) {
+ boolean remove(Predicate<Alarm> predicate, boolean reOrdering) {
boolean didRemove = false;
long newStart = 0; // recalculate endpoints as we go
long newEnd = Long.MAX_VALUE;
@@ -741,6 +759,9 @@
Alarm alarm = alarms.get(i);
if (predicate.test(alarm)) {
alarms.remove(i);
+ if (!reOrdering) {
+ decrementAlarmCount(alarm.uid);
+ }
didRemove = true;
if (alarm.alarmClock != null) {
mNextAlarmClockMayChange = true;
@@ -1734,6 +1755,15 @@
+ " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
+ " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
}
+ if (mAlarmsPerUid.get(callingUid, 0) >= mConstants.MAX_ALARMS_PER_UID) {
+ final String errorMsg =
+ "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID
+ + " reached for uid: " + UserHandle.formatUid(callingUid)
+ + ", callingPackage: " + callingPackage;
+ // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
+ Slog.wtf(TAG, errorMsg);
+ throw new UnsupportedOperationException(errorMsg);
+ }
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
interval, operation, directReceiver, listenerTag, flags, true, workSource,
alarmClock, callingUid, callingPackage);
@@ -1756,6 +1786,7 @@
} catch (RemoteException e) {
}
removeLocked(operation, directReceiver);
+ incrementAlarmCount(a.uid);
setImplLocked(a, false, doValidate);
}
@@ -2197,7 +2228,6 @@
? sdf.format(new Date(nowRTC - (nowELAPSED - time)))
: "-");
} while (i != mNextTickHistory);
- pw.println();
}
SystemServiceManager ssm = LocalServices.getService(SystemServiceManager.class);
@@ -2305,6 +2335,18 @@
if (!blocked) {
pw.println(" none");
}
+ pw.println();
+ pw.print(" Pending alarms per uid: [");
+ for (int i = 0; i < mAlarmsPerUid.size(); i++) {
+ if (i > 0) {
+ pw.print(", ");
+ }
+ UserHandle.formatUid(pw, mAlarmsPerUid.keyAt(i));
+ pw.print(":");
+ pw.print(mAlarmsPerUid.valueAt(i));
+ }
+ pw.println("]");
+ pw.println();
mAppWakeupHistory.dump(pw, " ", nowELAPSED);
@@ -3046,7 +3088,7 @@
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.matches(operation, directReceiver);
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3098,7 +3140,7 @@
final Predicate<Alarm> whichAlarms = (Alarm a) -> a.uid == uid;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3145,7 +3187,7 @@
final boolean oldHasTick = haveBatchesTimeTickAlarm(mAlarmBatches);
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3183,6 +3225,7 @@
}
}
+ // Only called for ephemeral apps
void removeForStoppedLocked(final int uid) {
if (uid == Process.SYSTEM_UID) {
Slog.wtf(TAG, "removeForStoppedLocked: Shouldn't for UID=" + uid);
@@ -3200,7 +3243,7 @@
};
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3237,7 +3280,7 @@
(Alarm a) -> UserHandle.getUserId(a.creatorUid) == userHandle;
for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
Batch b = mAlarmBatches.get(i);
- didRemove |= b.remove(whichAlarms);
+ didRemove |= b.remove(whichAlarms, false);
if (b.size() == 0) {
mAlarmBatches.remove(i);
}
@@ -3407,8 +3450,7 @@
return mConstants.ALLOW_WHILE_IDLE_LONG_TIME;
}
- boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
- final long nowRTC) {
+ boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED) {
boolean hasWakeup = false;
// batches are temporally sorted, so we need only pull from the
// start of the list until we either empty it or hit a batch
@@ -3984,7 +4026,7 @@
}
mLastTrigger = nowELAPSED;
- boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+ boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED);
if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
// if there are no wakeup alarms and the screen is off, we can
// delay what we have so far until the future.
@@ -4108,9 +4150,8 @@
case ALARM_EVENT: {
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
synchronized (mLock) {
- final long nowRTC = mInjector.getCurrentTimeMillis();
final long nowELAPSED = mInjector.getElapsedRealtime();
- triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+ triggerAlarmsLocked(triggerList, nowELAPSED);
updateNextAlarmClockLocked();
}
@@ -4719,7 +4760,7 @@
mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage,
UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
}
-
+ decrementAlarmCount(alarm.uid);
final BroadcastStats bs = inflight.mBroadcastStats;
bs.count++;
if (bs.nesting == 0) {
@@ -4747,6 +4788,27 @@
}
}
+ private void incrementAlarmCount(int uid) {
+ final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+ if (uidIndex >= 0) {
+ mAlarmsPerUid.setValueAt(uidIndex, mAlarmsPerUid.valueAt(uidIndex) + 1);
+ } else {
+ mAlarmsPerUid.put(uid, 1);
+ }
+ }
+
+ private void decrementAlarmCount(int uid) {
+ final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
+ if (uidIndex >= 0) {
+ final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1;
+ if (newCount > 0) {
+ mAlarmsPerUid.setValueAt(uidIndex, newCount);
+ } else {
+ mAlarmsPerUid.removeAt(uidIndex);
+ }
+ }
+ }
+
private class ShellCmd extends ShellCommand {
IAlarmManager getBinderService() {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index a85b69b..39f7f0f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -127,6 +127,7 @@
// discharge stats before the device dies.
private int mCriticalBatteryLevel;
+ // TODO: Current args don't work since "--unplugged" flag was purposefully removed.
private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
private static final String DUMPSYS_DATA_PATH = "/data/system/";
@@ -734,6 +735,7 @@
mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
}
+ // TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed.
private void logBatteryStatsLocked() {
IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
if (batteryInfoService == null) return;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 343cee1..c069729 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -41,7 +41,6 @@
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.shared.NetworkMonitorUtils.isValidationRequired;
-import static android.net.shared.NetworkParcelableUtil.toStableParcelable;
import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
@@ -2562,19 +2561,11 @@
final boolean partialConnectivity =
(msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
- // If user accepts partial connectivity network, NetworkMonitor
- // will skip https probing. It will make partial connectivity
- // network becomes valid. But user still need to know this
- // network is limited. So, it's needed to refer to
- // acceptPartialConnectivity to add
- // NET_CAPABILITY_PARTIAL_CONNECTIVITY into NetworkCapabilities
- // of this network. So that user can see "Limited connection"
- // in the settings.
|| (nai.networkMisc.acceptPartialConnectivity
&& nai.partialConnectivity);
// Once a network is determined to have partial connectivity, it cannot
// go back to full connectivity without a disconnect.
- final boolean partialConnectivityChange =
+ final boolean partialConnectivityChanged =
(partialConnectivity && !nai.partialConnectivity);
final boolean valid = (msg.arg1 == NETWORK_TEST_RESULT_VALID);
@@ -2585,17 +2576,6 @@
nai.captivePortalLoginNotified = true;
showNetworkNotification(nai, NotificationType.LOGGED_IN);
}
- // If this network has just connected and partial connectivity has just been
- // detected, tell NetworkMonitor if the user accepted partial connectivity on a
- // previous connect.
- if ((msg.arg1 == NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY)
- && nai.networkMisc.acceptPartialConnectivity) {
- try {
- nai.networkMonitor().notifyAcceptPartialConnectivity();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";
@@ -2625,7 +2605,7 @@
mNotifier.clearNotification(nai.network.netId,
NotificationType.LOST_INTERNET);
}
- } else if (partialConnectivityChange) {
+ } else if (partialConnectivityChanged) {
nai.partialConnectivity = partialConnectivity;
updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
}
@@ -3379,8 +3359,11 @@
// Tear down the network.
teardownUnneededNetwork(nai);
} else {
+ // Inform NetworkMonitor that partial connectivity is acceptable. This will likely
+ // result in a partial connectivity result which will be processed by
+ // maybeHandleNetworkMonitorMessage.
try {
- nai.networkMonitor().notifyAcceptPartialConnectivity();
+ nai.networkMonitor().setAcceptPartialConnectivity();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -3588,6 +3571,9 @@
// because we're already prompting the user to sign in.
if (nai == null || nai.everValidated || nai.everCaptivePortalDetected
|| !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated
+ // TODO: Once the value of acceptPartialConnectivity is moved to IpMemoryStore,
+ // we should reevaluate how to handle acceptPartialConnectivity when network just
+ // connected.
|| nai.networkMisc.acceptPartialConnectivity) {
return;
}
@@ -5390,7 +5376,7 @@
final long token = Binder.clearCallingIdentity();
try {
getNetworkStack().makeNetworkMonitor(
- toStableParcelable(nai.network), name, new NetworkMonitorCallbacks(nai));
+ nai.network, name, new NetworkMonitorCallbacks(nai));
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -6396,6 +6382,9 @@
// NetworkMonitor seeing the correct LinkProperties when starting.
// TODO: pass LinkProperties to the NetworkMonitor in the notifyNetworkConnected call.
try {
+ if (networkAgent.networkMisc.acceptPartialConnectivity) {
+ networkAgent.networkMonitor().setAcceptPartialConnectivity();
+ }
networkAgent.networkMonitor().notifyNetworkConnected();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 3ab3c34..833faa6 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -115,7 +115,8 @@
*
* Test: atest com.android.server.DeviceIdleControllerTest
*
- * Current idling state machine (as of Android 9 Pie). This can be visualized using Graphviz:
+ * Current idling state machine (as of Android Q). This can be visualized using Graphviz:
+ <pre>
digraph {
subgraph deep {
@@ -259,6 +260,7 @@
]
}
}
+ </pre>
*/
public class DeviceIdleController extends SystemService
implements AnyMotionDetector.DeviceIdleCallback {
diff --git a/services/core/java/com/android/server/DynamicAndroidService.java b/services/core/java/com/android/server/DynamicAndroidService.java
index 8488941..b02bfb1 100644
--- a/services/core/java/com/android/server/DynamicAndroidService.java
+++ b/services/core/java/com/android/server/DynamicAndroidService.java
@@ -25,6 +25,7 @@
import android.os.IDynamicAndroidService;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.Slog;
/**
@@ -34,6 +35,7 @@
public class DynamicAndroidService extends IDynamicAndroidService.Stub implements DeathRecipient {
private static final String TAG = "DynamicAndroidService";
private static final String NO_SERVICE_ERROR = "no gsiservice";
+ private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
private Context mContext;
private volatile IGsiService mGsiService;
@@ -66,12 +68,27 @@
private IGsiService getGsiService() throws RemoteException {
checkPermission();
- synchronized (this) {
- if (mGsiService == null) {
- mGsiService = connect(this);
- }
- return mGsiService;
+ if (!"running".equals(SystemProperties.get("init.svc.gsid"))) {
+ SystemProperties.set("ctl.start", "gsid");
}
+ for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) {
+ try {
+ Thread.sleep(sleepMs);
+ } catch (InterruptedException e) {
+ Slog.e(TAG, "Interrupted when waiting for GSID");
+ break;
+ }
+ if ("running".equals(SystemProperties.get("init.svc.gsid"))) {
+ synchronized (this) {
+ if (mGsiService == null) {
+ mGsiService = connect(this);
+ }
+ return mGsiService;
+ }
+ }
+ }
+ Slog.e(TAG, "Unable to start gsid");
+ return null;
}
private void checkPermission() {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index c2a0611..31010c9 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -102,6 +102,7 @@
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GnssBatchingProvider;
import com.android.server.location.GnssLocationProvider;
+import com.android.server.location.GnssMeasurementCorrectionsProvider;
import com.android.server.location.GnssMeasurementsProvider;
import com.android.server.location.GnssNavigationMessageProvider;
import com.android.server.location.GnssStatusListenerHelper;
@@ -195,6 +196,7 @@
private PassiveProvider mPassiveProvider; // track passive provider for special cases
private LocationBlacklist mBlacklist;
private GnssMeasurementsProvider mGnssMeasurementsProvider;
+ private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
@GuardedBy("mLock")
private String mLocationControllerExtraPackage;
@@ -309,9 +311,13 @@
AppOpsManager.WATCH_FOREGROUND_CHANGES,
new AppOpsManager.OnOpChangedInternalListener() {
public void onOpChanged(int op, String packageName) {
- synchronized (mLock) {
- onAppOpChangedLocked();
- }
+ // onOpChanged invoked on ui thread, move to our thread to reduce risk of
+ // blocking ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onAppOpChangedLocked();
+ }
+ });
}
});
mPackageManager.addOnPermissionsChangeListener(
@@ -501,6 +507,8 @@
}
if (broadcast) {
+ // needs to be sent to everyone because we don't know which user may have changed
+ // LOCATION_MODE state.
mContext.sendBroadcastAsUser(
new Intent(LocationManager.MODE_CHANGED_ACTION),
UserHandle.ALL);
@@ -755,6 +763,8 @@
mGnssStatusProvider = gnssProvider.getGnssStatusProvider();
mNetInitiatedListener = gnssProvider.getNetInitiatedListener();
mGnssMeasurementsProvider = gnssProvider.getGnssMeasurementsProvider();
+ mGnssMeasurementCorrectionsProvider =
+ gnssProvider.getGnssMeasurementCorrectionsProvider();
mGnssNavigationMessageProvider = gnssProvider.getGnssNavigationMessageProvider();
mGpsGeofenceProxy = gnssProvider.getGpsGeofenceProxy();
}
@@ -1212,6 +1222,13 @@
"-" + mName,
mCurrentUserId);
}
+
+ // needs to be sent to all users because whether or not a provider is enabled for
+ // a given user is complicated... we broadcast to everyone and let them figure it
+ // out via isProviderEnabled()
+ Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
+ intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
}
if (useable == mUseable) {
@@ -1232,10 +1249,6 @@
}
updateProviderUseableLocked(this);
-
- mContext.sendBroadcastAsUser(
- new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
- UserHandle.ALL);
}
@GuardedBy("mLock")
@@ -1811,12 +1824,7 @@
@GuardedBy("mLock")
private void removeProviderLocked(LocationProvider provider) {
if (mProviders.remove(provider)) {
- long identity = Binder.clearCallingIdentity();
- try {
- provider.onUseableChangedLocked(false);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ provider.onUseableChangedLocked(false);
}
}
@@ -2095,7 +2103,9 @@
WorkSource worksource = new WorkSource();
ProviderRequest providerRequest = new ProviderRequest();
- if (records != null && !records.isEmpty()) {
+ // if provider is not active, it should not respond to requests
+
+ if (mProviders.contains(provider) && records != null && !records.isEmpty()) {
long backgroundThrottleInterval;
long identity = Binder.clearCallingIdentity();
@@ -2916,22 +2926,28 @@
mContext.enforceCallingPermission(
android.Manifest.permission.LOCATION_HARDWARE,
"Location Hardware permission not granted to inject GNSS measurement corrections.");
- if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+ if (!hasGnssPermissions(packageName)) {
Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
- } else {
- mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
+ return;
}
+ if (mGnssMeasurementCorrectionsProvider == null) {
+ Slog.e(TAG, "Can not inject GNSS corrections. GNSS measurement corrections provider "
+ + "not available.");
+ return;
+ }
+ mGnssMeasurementCorrectionsProvider.injectGnssMeasurementCorrections(
+ measurementCorrections);
}
@Override
- public int getGnssCapabilities(String packageName) {
+ public long getGnssCapabilities(String packageName) {
mContext.enforceCallingPermission(
android.Manifest.permission.LOCATION_HARDWARE,
- "Location Hardware permission not granted to obrain GNSS chipset capabilities.");
- if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
+ "Location Hardware permission not granted to obtain GNSS chipset capabilities.");
+ if (!hasGnssPermissions(packageName) || mGnssMeasurementCorrectionsProvider == null) {
return -1;
}
- return mGnssMeasurementsProvider.getGnssCapabilities();
+ return mGnssMeasurementCorrectionsProvider.getCapabilities();
}
@Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 5582ad7..61a7182 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -39,7 +39,6 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_TETHERING;
-import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.annotation.NonNull;
@@ -62,6 +61,7 @@
import android.net.RouteInfo;
import android.net.TetherStatsParcel;
import android.net.UidRange;
+import android.net.UidRangeParcel;
import android.net.util.NetdService;
import android.os.BatteryStats;
import android.os.Binder;
@@ -69,7 +69,6 @@
import android.os.IBinder;
import android.os.INetworkActivityListener;
import android.os.INetworkManagementService;
-import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -80,6 +79,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.telephony.DataConnectionRealTimeInfo;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -110,13 +110,11 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.CountDownLatch;
/**
* @hide
*/
-public class NetworkManagementService extends INetworkManagementService.Stub
- implements Watchdog.Monitor {
+public class NetworkManagementService extends INetworkManagementService.Stub {
/**
* Helper class that encapsulates NetworkManagementService dependencies and makes them
@@ -136,8 +134,6 @@
private static final String TAG = "NetworkManagement";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String NETD_TAG = "NetdConnector";
- static final String NETD_SERVICE_NAME = "netd";
private static final int MAX_UID_RANGES_PER_COMMAND = 10;
@@ -147,44 +143,6 @@
*/
public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
- static class NetdResponseCode {
- /* Keep in sync with system/netd/server/ResponseCode.h */
- public static final int InterfaceListResult = 110;
- public static final int TetherInterfaceListResult = 111;
- public static final int TetherDnsFwdTgtListResult = 112;
- public static final int TtyListResult = 113;
- public static final int TetheringStatsListResult = 114;
-
- public static final int TetherStatusResult = 210;
- public static final int IpFwdStatusResult = 211;
- public static final int InterfaceGetCfgResult = 213;
- public static final int SoftapStatusResult = 214;
- public static final int InterfaceRxCounterResult = 216;
- public static final int InterfaceTxCounterResult = 217;
- public static final int QuotaCounterResult = 220;
- public static final int TetheringStatsResult = 221;
- public static final int DnsProxyQueryResult = 222;
- public static final int ClatdStatusResult = 223;
-
- public static final int InterfaceChange = 600;
- public static final int BandwidthControl = 601;
- public static final int InterfaceClassActivity = 613;
- public static final int InterfaceAddressChange = 614;
- public static final int InterfaceDnsServerInfo = 615;
- public static final int RouteChange = 616;
- public static final int StrictCleartext = 617;
- }
-
- /**
- * String indicating a softap command.
- */
- static final String SOFT_AP_COMMAND = "softap";
-
- /**
- * String passed back to netd connector indicating softap command success.
- */
- static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
-
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
static final boolean MODIFY_OPERATION_ADD = true;
@@ -195,12 +153,6 @@
*/
private final Context mContext;
- /**
- * connector object for communicating with netd
- */
- private final NativeDaemonConnector mConnector;
-
- private final Handler mFgHandler;
private final Handler mDaemonHandler;
private final SystemServices mServices;
@@ -211,9 +163,6 @@
private IBatteryStats mBatteryStats;
- private final Thread mThread;
- private CountDownLatch mConnectedSignal = new CountDownLatch(1);
-
private final RemoteCallbackList<INetworkManagementEventObserver> mObservers =
new RemoteCallbackList<>();
@@ -305,32 +254,14 @@
* @param context Binder context for this service
*/
private NetworkManagementService(
- Context context, String socket, SystemServices services) {
+ Context context, SystemServices services) {
mContext = context;
mServices = services;
- // make sure this is on the same looper as our NativeDaemonConnector for sync purposes
- mFgHandler = new Handler(FgThread.get().getLooper());
-
- // Don't need this wake lock, since we now have a time stamp for when
- // the network actually went inactive. (It might be nice to still do this,
- // but I don't want to do it through the power manager because that pollutes the
- // battery stats history with pointless noise.)
- //PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- PowerManager.WakeLock wl = null; //pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NETD_TAG);
-
- mConnector = new NativeDaemonConnector(
- new NetdCallbackReceiver(), socket, 10, NETD_TAG, 160, wl,
- FgThread.get().getLooper());
- mThread = new Thread(mConnector, NETD_TAG);
-
mDaemonHandler = new Handler(FgThread.get().getLooper());
mNetdUnsolicitedEventListener = new NetdUnsolicitedEventListener();
- // Add ourself to the Watchdog monitors.
- Watchdog.getInstance().addMonitor(this);
-
mServices.registerLocalService(new LocalService());
synchronized (mTetheringStatsProviders) {
@@ -340,25 +271,17 @@
@VisibleForTesting
NetworkManagementService() {
- mConnector = null;
mContext = null;
mDaemonHandler = null;
- mFgHandler = null;
- mThread = null;
mServices = null;
mNetdUnsolicitedEventListener = null;
}
- static NetworkManagementService create(Context context, String socket, SystemServices services)
+ static NetworkManagementService create(Context context, SystemServices services)
throws InterruptedException {
final NetworkManagementService service =
- new NetworkManagementService(context, socket, services);
- final CountDownLatch connectedSignal = service.mConnectedSignal;
+ new NetworkManagementService(context, services);
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
- service.mThread.start();
- if (DBG) Slog.d(TAG, "Awaiting socket connection");
- connectedSignal.await();
- if (DBG) Slog.d(TAG, "Connected");
if (DBG) Slog.d(TAG, "Connecting native netd service");
service.connectNativeNetdService();
if (DBG) Slog.d(TAG, "Connected");
@@ -366,7 +289,7 @@
}
public static NetworkManagementService create(Context context) throws InterruptedException {
- return create(context, NETD_SERVICE_NAME, new SystemServices());
+ return create(context, new SystemServices());
}
public void systemReady() {
@@ -810,212 +733,6 @@
}
//
- // Netd Callback handling
- //
-
- private class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
- @Override
- public void onDaemonConnected() {
- Slog.i(TAG, "onDaemonConnected()");
- // event is dispatched from internal NDC thread, so we prepare the
- // daemon back on main thread.
- if (mConnectedSignal != null) {
- // The system is booting and we're connecting to netd for the first time.
- mConnectedSignal.countDown();
- mConnectedSignal = null;
- } else {
- // We're reconnecting to netd after the socket connection
- // was interrupted (e.g., if it crashed).
- mFgHandler.post(new Runnable() {
- @Override
- public void run() {
- connectNativeNetdService();
- prepareNativeDaemon();
- }
- });
- }
- }
-
- @Override
- public boolean onCheckHoldWakeLock(int code) {
- return code == NetdResponseCode.InterfaceClassActivity;
- }
-
- @Override
- public boolean onEvent(int code, String raw, String[] cooked) {
- String errorMessage = String.format("Invalid event from daemon (%s)", raw);
- switch (code) {
- case NetdResponseCode.InterfaceChange:
- /*
- * a network interface change occured
- * Format: "NNN Iface added <name>"
- * "NNN Iface removed <name>"
- * "NNN Iface changed <name> <up/down>"
- * "NNN Iface linkstatus <name> <up/down>"
- */
- if (cooked.length < 4 || !cooked[1].equals("Iface")) {
- throw new IllegalStateException(errorMessage);
- }
- if (cooked[2].equals("added")) {
- notifyInterfaceAdded(cooked[3]);
- return true;
- } else if (cooked[2].equals("removed")) {
- notifyInterfaceRemoved(cooked[3]);
- return true;
- } else if (cooked[2].equals("changed") && cooked.length == 5) {
- notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
- return true;
- } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
- notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
- return true;
- }
- throw new IllegalStateException(errorMessage);
- // break;
- case NetdResponseCode.BandwidthControl:
- /*
- * Bandwidth control needs some attention
- * Format: "NNN limit alert <alertName> <ifaceName>"
- */
- if (cooked.length < 5 || !cooked[1].equals("limit")) {
- throw new IllegalStateException(errorMessage);
- }
- if (cooked[2].equals("alert")) {
- notifyLimitReached(cooked[3], cooked[4]);
- return true;
- }
- throw new IllegalStateException(errorMessage);
- // break;
- case NetdResponseCode.InterfaceClassActivity:
- /*
- * An network interface class state changed (active/idle)
- * Format: "NNN IfaceClass <active/idle> <label>"
- */
- if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
- throw new IllegalStateException(errorMessage);
- }
- long timestampNanos = 0;
- int processUid = -1;
- if (cooked.length >= 5) {
- try {
- timestampNanos = Long.parseLong(cooked[4]);
- if (cooked.length == 6) {
- processUid = Integer.parseInt(cooked[5]);
- }
- } catch(NumberFormatException ne) {}
- } else {
- timestampNanos = SystemClock.elapsedRealtimeNanos();
- }
- boolean isActive = cooked[2].equals("active");
- notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
- isActive, timestampNanos, processUid, false);
- return true;
- // break;
- case NetdResponseCode.InterfaceAddressChange:
- /*
- * A network address change occurred
- * Format: "NNN Address updated <addr> <iface> <flags> <scope>"
- * "NNN Address removed <addr> <iface> <flags> <scope>"
- */
- if (cooked.length < 7 || !cooked[1].equals("Address")) {
- throw new IllegalStateException(errorMessage);
- }
-
- String iface = cooked[4];
- LinkAddress address;
- try {
- int flags = Integer.parseInt(cooked[5]);
- int scope = Integer.parseInt(cooked[6]);
- address = new LinkAddress(cooked[3], flags, scope);
- } catch(NumberFormatException e) { // Non-numeric lifetime or scope.
- throw new IllegalStateException(errorMessage, e);
- } catch(IllegalArgumentException e) { // Malformed/invalid IP address.
- throw new IllegalStateException(errorMessage, e);
- }
-
- if (cooked[2].equals("updated")) {
- notifyAddressUpdated(iface, address);
- } else {
- notifyAddressRemoved(iface, address);
- }
- return true;
- // break;
- case NetdResponseCode.InterfaceDnsServerInfo:
- /*
- * Information about available DNS servers has been received.
- * Format: "NNN DnsInfo servers <interface> <lifetime> <servers>"
- */
- long lifetime; // Actually a 32-bit unsigned integer.
-
- if (cooked.length == 6 &&
- cooked[1].equals("DnsInfo") &&
- cooked[2].equals("servers")) {
- try {
- lifetime = Long.parseLong(cooked[4]);
- } catch (NumberFormatException e) {
- throw new IllegalStateException(errorMessage);
- }
- String[] servers = cooked[5].split(",");
- notifyInterfaceDnsServerInfo(cooked[3], lifetime, servers);
- }
- return true;
- // break;
- case NetdResponseCode.RouteChange:
- /*
- * A route has been updated or removed.
- * Format: "NNN Route <updated|removed> <dst> [via <gateway] [dev <iface>]"
- */
- if (!cooked[1].equals("Route") || cooked.length < 6) {
- throw new IllegalStateException(errorMessage);
- }
-
- String via = null;
- String dev = null;
- boolean valid = true;
- for (int i = 4; (i + 1) < cooked.length && valid; i += 2) {
- if (cooked[i].equals("dev")) {
- if (dev == null) {
- dev = cooked[i+1];
- } else {
- valid = false; // Duplicate interface.
- }
- } else if (cooked[i].equals("via")) {
- if (via == null) {
- via = cooked[i+1];
- } else {
- valid = false; // Duplicate gateway.
- }
- } else {
- valid = false; // Unknown syntax.
- }
- }
- if (valid) {
- try {
- // InetAddress.parseNumericAddress(null) inexplicably returns ::1.
- InetAddress gateway = null;
- if (via != null) gateway = InetAddress.parseNumericAddress(via);
- RouteInfo route = new RouteInfo(new IpPrefix(cooked[3]), gateway, dev);
- notifyRouteChange(cooked[2].equals("updated"), route);
- return true;
- } catch (IllegalArgumentException e) {}
- }
- throw new IllegalStateException(errorMessage);
- // break;
- case NetdResponseCode.StrictCleartext:
- final int uid = Integer.parseInt(cooked[1]);
- final byte[] firstPacket = HexDump.hexStringToByteArray(cooked[2]);
- try {
- ActivityManager.getService().notifyCleartextNetwork(uid, firstPacket);
- } catch (RemoteException ignored) {
- }
- break;
- default: break;
- }
- return false;
- }
- }
-
-
- //
// INetworkManagementService members
//
@Override
@@ -1028,6 +745,46 @@
}
}
+ /**
+ * Convert InterfaceConfiguration to InterfaceConfigurationParcel with given ifname.
+ */
+ private static InterfaceConfigurationParcel toStableParcel(InterfaceConfiguration cfg,
+ String iface) {
+ InterfaceConfigurationParcel cfgParcel = new InterfaceConfigurationParcel();
+ cfgParcel.ifName = iface;
+ String hwAddr = cfg.getHardwareAddress();
+ if (!TextUtils.isEmpty(hwAddr)) {
+ cfgParcel.hwAddr = hwAddr;
+ } else {
+ cfgParcel.hwAddr = "";
+ }
+ cfgParcel.ipv4Addr = cfg.getLinkAddress().getAddress().getHostAddress();
+ cfgParcel.prefixLength = cfg.getLinkAddress().getPrefixLength();
+ ArrayList<String> flags = new ArrayList<>();
+ for (String flag : cfg.getFlags()) {
+ flags.add(flag);
+ }
+ cfgParcel.flags = flags.toArray(new String[0]);
+
+ return cfgParcel;
+ }
+
+ /**
+ * Construct InterfaceConfiguration from InterfaceConfigurationParcel.
+ */
+ public static InterfaceConfiguration fromStableParcel(InterfaceConfigurationParcel p) {
+ InterfaceConfiguration cfg = new InterfaceConfiguration();
+ cfg.setHardwareAddress(p.hwAddr);
+
+ final InetAddress addr = NetworkUtils.numericToInetAddress(p.ipv4Addr);
+ cfg.setLinkAddress(new LinkAddress(addr, p.prefixLength));
+ for (String flag : p.flags) {
+ cfg.setFlag(flag);
+ }
+
+ return cfg;
+ }
+
@Override
public InterfaceConfiguration getInterfaceConfig(String iface) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1039,7 +796,7 @@
}
try {
- final InterfaceConfiguration cfg = InterfaceConfiguration.fromParcel(result);
+ final InterfaceConfiguration cfg = fromStableParcel(result);
return cfg;
} catch (IllegalArgumentException iae) {
throw new IllegalStateException("Invalid InterfaceConfigurationParcel", iae);
@@ -1054,7 +811,7 @@
throw new IllegalStateException("Null LinkAddress given");
}
- final InterfaceConfigurationParcel cfgParcel = cfg.toParcel(iface);
+ final InterfaceConfigurationParcel cfgParcel = toStableParcel(cfg, iface);
try {
mNetdService.interfaceSetCfg(cfgParcel);
@@ -1397,42 +1154,6 @@
}
@Override
- public String[] listTtys() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- return NativeDaemonEvent.filterMessageList(
- mConnector.executeForList("list_ttys"), TtyListResult);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void attachPppd(
- String tty, String localAddr, String remoteAddr, String dns1Addr, String dns2Addr) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("pppd", "attach", tty,
- NetworkUtils.numericToInetAddress(localAddr).getHostAddress(),
- NetworkUtils.numericToInetAddress(remoteAddr).getHostAddress(),
- NetworkUtils.numericToInetAddress(dns1Addr).getHostAddress(),
- NetworkUtils.numericToInetAddress(dns2Addr).getHostAddress());
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void detachPppd(String tty) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- try {
- mConnector.execute("pppd", "detach", tty);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
public void addIdleTimer(String iface, int timeout, final int type) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -1718,12 +1439,27 @@
}
}
+ private static UidRangeParcel makeUidRangeParcel(int start, int stop) {
+ UidRangeParcel range = new UidRangeParcel();
+ range.start = start;
+ range.stop = stop;
+ return range;
+ }
+
+ private static UidRangeParcel[] toStableParcels(UidRange[] ranges) {
+ UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
+ for (int i = 0; i < ranges.length; i++) {
+ stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop);
+ }
+ return stableRanges;
+ }
+
@Override
public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
throws ServiceSpecificException {
mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
try {
- mNetdService.networkRejectNonSecureVpn(add, uidRanges);
+ mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
} catch (ServiceSpecificException e) {
Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
+ ": netd command failed", e);
@@ -1892,7 +1628,7 @@
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mNetdService.networkAddUidRanges(netId, ranges);
+ mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -1902,7 +1638,7 @@
public void removeVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mNetdService.networkRemoveUidRanges(netId, ranges);
+ mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException(e);
}
@@ -1940,7 +1676,7 @@
private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
// UID ranges to close sockets on.
- UidRange[] ranges;
+ UidRangeParcel[] ranges;
// UID ranges whose sockets we won't touch.
int[] exemptUids;
@@ -1948,10 +1684,10 @@
if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
if (getFirewallType(chain) == FIREWALL_WHITELIST) {
// Close all sockets on all non-system UIDs...
- ranges = new UidRange[] {
+ ranges = new UidRangeParcel[] {
// TODO: is there a better way of finding all existing users? If so, we could
// specify their ranges here.
- new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
+ makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
};
// ... except for the UIDs that have allow rules.
synchronized (mRulesLock) {
@@ -1978,11 +1714,11 @@
// Close sockets for every UID that has a deny rule...
synchronized (mRulesLock) {
final SparseIntArray rules = getUidFirewallRulesLR(chain);
- ranges = new UidRange[rules.size()];
+ ranges = new UidRangeParcel[rules.size()];
for (int i = 0; i < ranges.length; i++) {
if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
int uid = rules.keyAt(i);
- ranges[numUids] = new UidRange(uid, uid);
+ ranges[numUids] = makeUidRangeParcel(uid, uid);
numUids++;
}
}
@@ -2238,22 +1974,10 @@
}
}
- /** {@inheritDoc} */
- @Override
- public void monitor() {
- if (mConnector != null) {
- mConnector.monitor();
- }
- }
-
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.println("NetworkManagementService NativeDaemonConnector Log:");
- mConnector.dump(fd, pw, args);
- pw.println();
-
pw.print("mMobileActivityFromRadio="); pw.print(mMobileActivityFromRadio);
pw.print(" mLastPowerStateFromRadio="); pw.println(mLastPowerStateFromRadio);
pw.print("mNetworkActive="); pw.println(mNetworkActive);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index f416110..077920c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -21,6 +21,9 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -74,6 +77,7 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.DropBoxManager;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
@@ -208,6 +212,13 @@
private static final boolean ENABLE_LEGACY_GREYLIST = SystemProperties
.getBoolean(StorageManager.PROP_LEGACY_GREYLIST, true);
+ /**
+ * If {@code 1}, enables the isolated storage feature. If {@code -1},
+ * disables the isolated storage feature. If {@code 0}, uses the default
+ * value from the build system.
+ */
+ private static final String ISOLATED_STORAGE_ENABLED = "isolated_storage_enabled";
+
public static class Lifecycle extends SystemService {
private StorageManagerService mStorageManagerService;
@@ -294,6 +305,19 @@
private static final String ATTR_LAST_TRIM_MILLIS = "lastTrimMillis";
private static final String ATTR_LAST_BENCH_MILLIS = "lastBenchMillis";
+ private static final String[] LEGACY_STORAGE_PERMISSIONS = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE
+ };
+
+ private static final String[] ALL_STORAGE_PERMISSIONS = {
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_MEDIA_AUDIO,
+ Manifest.permission.READ_MEDIA_VIDEO,
+ Manifest.permission.READ_MEDIA_IMAGES
+ };
+
private final AtomicFile mSettingsFile;
/**
@@ -797,7 +821,7 @@
}
});
// For now, simply clone property when it changes
- DeviceConfig.addOnPropertyChangedListener(DeviceConfig.Storage.NAMESPACE,
+ DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_STORAGE,
mContext.getMainExecutor(), (namespace, name, value) -> {
refreshIsolatedStorageSettings();
});
@@ -837,8 +861,7 @@
// Always copy value from newer DeviceConfig location
Settings.Global.putString(mResolver,
Settings.Global.ISOLATED_STORAGE_REMOTE,
- DeviceConfig.getProperty(DeviceConfig.Storage.NAMESPACE,
- DeviceConfig.Storage.ISOLATED_STORAGE_ENABLED));
+ DeviceConfig.getProperty(DeviceConfig.NAMESPACE_STORAGE, ISOLATED_STORAGE_ENABLED));
final int local = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ISOLATED_STORAGE_LOCAL, 0);
@@ -1668,16 +1691,18 @@
synchronized (mLock) {
final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage();
- if (mLastIsolatedStorage == thisIsolatedStorage) {
- // Nothing changed since last boot; keep rolling forward
- return;
- } else if (thisIsolatedStorage) {
- // This boot enables isolated storage; apply legacy behavior
- applyLegacyStorage();
+ if (mLastIsolatedStorage != thisIsolatedStorage) {
+ if (thisIsolatedStorage) {
+ // This boot enables isolated storage; apply legacy behavior
+ applyLegacyStorage();
+ }
+
+ // Always remember the new state we just booted with
+ writeSettingsLocked();
}
- // Always remember the new state we just booted with
- writeSettingsLocked();
+ // Execute special logic to recover certain devices
+ recoverFrom128872367();
}
}
@@ -1685,23 +1710,27 @@
* If we're enabling isolated storage, we need to remember which existing
* apps have already been using shared storage, and grant them legacy access
* to keep them running smoothly.
+ *
+ * @see com.android.server.pm.permission.PermissionManagerService
+ * #applyLegacyStoragePermissionModel
*/
private void applyLegacyStorage() {
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
for (int userId : um.getUserIds()) {
+ final UserHandle user = UserHandle.of(userId);
final PackageManager pm;
try {
- pm = mContext.createPackageContextAsUser(mContext.getPackageName(),
- 0, UserHandle.of(userId)).getPackageManager();
+ pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
+ user).getPackageManager();
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(e);
}
- final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(new String[] {
- android.Manifest.permission.READ_EXTERNAL_STORAGE,
- android.Manifest.permission.WRITE_EXTERNAL_STORAGE
- }, MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
+ final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(
+ LEGACY_STORAGE_PERMISSIONS,
+ MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
+ | GET_PERMISSIONS);
for (PackageInfo pkg : pkgs) {
final int uid = pkg.applicationInfo.uid;
final String packageName = pkg.applicationInfo.packageName;
@@ -1714,8 +1743,28 @@
Log.d(TAG, "Found " + uid + " " + packageName
+ " with granted storage access, last accessed " + lastAccess);
if (lastAccess > 0) {
- appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE,
- uid, packageName, AppOpsManager.MODE_ALLOWED);
+ appOps.setUidMode(AppOpsManager.OP_LEGACY_STORAGE, uid,
+ AppOpsManager.MODE_ALLOWED);
+
+ // Grandfather pre-Q app by granting all permissions and fixing them. The user
+ // needs to uninstall the app to revoke the permissions.
+ // TODO: Deal with shard Uids
+ if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
+ for (String perm : ALL_STORAGE_PERMISSIONS) {
+ if (ArrayUtils.contains(pkg.requestedPermissions, perm)) {
+ pm.grantRuntimePermission(packageName, perm, user);
+
+ int flags = FLAG_PERMISSION_SYSTEM_FIXED;
+ if (!ArrayUtils.contains(LEGACY_STORAGE_PERMISSIONS, perm)) {
+ flags |= FLAG_PERMISSION_HIDDEN;
+ }
+
+ pm.updatePermissionFlags(perm, packageName,
+ FLAG_PERMISSION_SYSTEM_FIXED | FLAG_PERMISSION_HIDDEN,
+ flags, user);
+ }
+ }
+ }
}
}
}
@@ -1734,6 +1783,69 @@
return maxTime;
}
+ /**
+ * In b/128872367 we lost all app-ops on devices in the wild. This logic
+ * attempts to detect and recover from this by granting
+ * {@link AppOpsManager#OP_LEGACY_STORAGE} to any apps installed before
+ * isolated storage was enabled.
+ */
+ private void recoverFrom128872367() {
+ // We're interested in packages that were installed or updated between
+ // 1/1/2014 and 12/17/2018
+ final long START_TIMESTAMP = 1388534400000L;
+ final long END_TIMESTAMP = 1545004800000L;
+
+ final PackageManager pm = mContext.getPackageManager();
+ final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
+
+ boolean activeDuringWindow = false;
+ List<PackageInfo> pendingHolders = new ArrayList<>();
+
+ for (int userId : um.getUserIds()) {
+ final List<PackageInfo> pkgs = pm.getInstalledPackagesAsUser(MATCH_UNINSTALLED_PACKAGES
+ | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId);
+ for (PackageInfo pkg : pkgs) {
+ // Determine if any apps on this device had been installed or
+ // updated during the period where the feature was disabled
+ activeDuringWindow |= (pkg.firstInstallTime > START_TIMESTAMP
+ && pkg.firstInstallTime < END_TIMESTAMP);
+ activeDuringWindow |= (pkg.lastUpdateTime > START_TIMESTAMP
+ && pkg.lastUpdateTime < END_TIMESTAMP);
+
+ // This app should hold legacy op if they were installed before
+ // the cutoff; we only check the end boundary here so that
+ // include system apps, which are always installed on 1/1/2009.
+ final boolean shouldHold = (pkg.firstInstallTime < END_TIMESTAMP);
+ final boolean doesHold = (appOps.checkOpNoThrow(OP_LEGACY_STORAGE,
+ pkg.applicationInfo.uid,
+ pkg.applicationInfo.packageName) == MODE_ALLOWED);
+
+ if (doesHold) {
+ Slog.d(TAG, "Found " + pkg + " holding legacy op; skipping recovery");
+ return;
+ } else if (shouldHold) {
+ Slog.d(TAG, "Found " + pkg + " that should hold legacy op");
+ pendingHolders.add(pkg);
+ }
+ }
+ }
+
+ if (!activeDuringWindow) {
+ Slog.d(TAG, "No packages were active during the time window; skipping grants");
+ return;
+ }
+
+ // If we made it this far, nobody actually holds the legacy op, which
+ // means we probably lost the database, and we should grant the op to
+ // all the apps we identified.
+ for (PackageInfo pkg : pendingHolders) {
+ appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE,
+ pkg.applicationInfo.uid,
+ pkg.applicationInfo.packageName, AppOpsManager.MODE_ALLOWED);
+ }
+ }
+
private void systemReady() {
LocalServices.getService(ActivityTaskManagerInternal.class)
.registerScreenObserver(this);
@@ -3741,6 +3853,7 @@
case "com.facebook.katana": // b/123996076
case "jp.naver.line.android": // b/124767356
case "com.mxtech.videoplayer.ad": // b/124531483
+ case "com.whatsapp": // b/124766614
return Zygote.MOUNT_EXTERNAL_LEGACY;
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index d6fdbe3..26896f5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -625,6 +625,11 @@
r.callingPackage = callingPackage;
r.callerUid = Binder.getCallingUid();
r.callerPid = Binder.getCallingPid();
+ if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) {
+ throw new IllegalArgumentException(
+ "PhoneStateListener cannot concurrently listen on multiple " +
+ "subscriptions. Previously registered on subId: " + r.subId);
+ }
// Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
// force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6270106..e357ce8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1600,6 +1600,11 @@
"BIND_TREAT_LIKE_ACTIVITY");
}
+ if ((flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0 && !isCallerSystem) {
+ throw new SecurityException("Non-system caller (pid=" + Binder.getCallingPid()
+ + ") set BIND_SCHEDULE_LIKE_TOP_APP when binding service " + service);
+ }
+
if ((flags & Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0 && !isCallerSystem) {
throw new SecurityException(
"Non-system caller " + caller + " (pid=" + Binder.getCallingPid()
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 178a55b..97cc756 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1273,11 +1273,13 @@
static final class ProcessChangeItem {
static final int CHANGE_ACTIVITIES = 1<<0;
+ static final int CHANGE_FOREGROUND_SERVICES = 1<<1;
int changes;
int uid;
int pid;
int processState;
boolean foregroundActivities;
+ int foregroundServiceTypes;
}
static final class UidObserverRegistration {
@@ -2934,8 +2936,9 @@
taskRoot);
}
}
- if (mContentCaptureService != null
- && (event == Event.ACTIVITY_PAUSED || event == Event.ACTIVITY_RESUMED)) {
+ if (mContentCaptureService != null && (event == Event.ACTIVITY_PAUSED
+ || event == Event.ACTIVITY_RESUMED || event == Event.ACTIVITY_STOPPED
+ || event == Event.ACTIVITY_DESTROYED)) {
mContentCaptureService.notifyActivityEvent(userId, activity, event);
}
}
@@ -3079,6 +3082,13 @@
observer.onForegroundActivitiesChanged(item.pid, item.uid,
item.foregroundActivities);
}
+ if ((item.changes & ProcessChangeItem.CHANGE_FOREGROUND_SERVICES) != 0) {
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "FOREGROUND SERVICES CHANGED pid=" + item.pid + " uid="
+ + item.uid + ": " + item.foregroundServiceTypes);
+ observer.onForegroundServicesChanged(item.pid, item.uid,
+ item.foregroundServiceTypes);
+ }
}
} catch (RemoteException e) {
}
@@ -3093,6 +3103,47 @@
}
}
+ @GuardedBy("this")
+ ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) {
+ int i = mPendingProcessChanges.size()-1;
+ ActivityManagerService.ProcessChangeItem item = null;
+ while (i >= 0) {
+ item = mPendingProcessChanges.get(i);
+ if (item.pid == pid) {
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Re-using existing item: " + item);
+ break;
+ }
+ i--;
+ }
+
+ if (i < 0) {
+ // No existing item in pending changes; need a new one.
+ final int NA = mAvailProcessChanges.size();
+ if (NA > 0) {
+ item = mAvailProcessChanges.remove(NA-1);
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Retrieving available item: " + item);
+ } else {
+ item = new ActivityManagerService.ProcessChangeItem();
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "Allocating new item: " + item);
+ }
+ item.changes = 0;
+ item.pid = pid;
+ item.uid = uid;
+ if (mPendingProcessChanges.size() == 0) {
+ if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+ "*** Enqueueing dispatch processes changed!");
+ mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
+ .sendToTarget();
+ }
+ mPendingProcessChanges.add(item);
+ }
+
+ return item;
+ }
+
private void dispatchProcessDied(int pid, int uid) {
int i = mProcessObservers.beginBroadcast();
while (i > 0) {
@@ -5492,6 +5543,12 @@
}
}
+ private boolean isAppBad(ApplicationInfo info) {
+ synchronized (this) {
+ return mAppErrors.isBadProcessLocked(info);
+ }
+ }
+
// NOTE: this is an internal method used by the OnShellCommand implementation only and should
// be guarded by permission checking.
int getUidState(int uid) {
@@ -16269,11 +16326,12 @@
@GuardedBy("this")
final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
int fgServiceTypes, boolean oomAdj) {
+ proc.setHasForegroundServices(isForeground, fgServiceTypes);
+
final boolean hasFgServiceLocationType =
(fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
if (isForeground != proc.hasForegroundServices()
|| proc.hasLocationForegroundServices() != hasFgServiceLocationType) {
- proc.setHasForegroundServices(isForeground, fgServiceTypes);
ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
proc.info.uid);
if (isForeground) {
@@ -16302,6 +16360,13 @@
updateOomAdjLocked();
}
}
+
+ if (proc.getForegroundServiceTypes() != fgServiceTypes) {
+ proc.setReportedForegroundServiceTypes(fgServiceTypes);
+ ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid);
+ item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
+ item.foregroundServiceTypes = fgServiceTypes;
+ }
}
// TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
@@ -18078,6 +18143,11 @@
}
@Override
+ public boolean isAppBad(ApplicationInfo info) {
+ return ActivityManagerService.this.isAppBad(info);
+ }
+
+ @Override
public void clearPendingBackup(int userId) {
ActivityManagerService.this.clearPendingBackup(userId);
}
@@ -18090,6 +18160,34 @@
public void prepareForPossibleShutdown() {
ActivityManagerService.this.prepareForPossibleShutdown();
}
+
+ @Override
+ public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
+ synchronized (ActivityManagerService.this) {
+ for (int i = 0; i < mProcessList.mLruProcesses.size(); i++) {
+ final ProcessRecord pr = mProcessList.mLruProcesses.get(i);
+ if (pr.uid != uid) {
+ continue;
+ }
+
+ if ((pr.getForegroundServiceTypes() & foregroundServicetype) != 0) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void registerProcessObserver(IProcessObserver processObserver) {
+ ActivityManagerService.this.registerProcessObserver(processObserver);
+ }
+
+ @Override
+ public void unregisterProcessObserver(IProcessObserver processObserver) {
+ ActivityManagerService.this.unregisterProcessObserver(processObserver);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 1f21160..9216343 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -211,7 +211,7 @@
mPendingCompactionProcesses.add(app);
mCompactionHandler.sendMessage(
mCompactionHandler.obtainMessage(
- COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
+ COMPACT_PROCESS_MSG, app.setAdj, app.setProcState));
}
@GuardedBy("mAm")
@@ -220,7 +220,7 @@
mPendingCompactionProcesses.add(app);
mCompactionHandler.sendMessage(
mCompactionHandler.obtainMessage(
- COMPACT_PROCESS_MSG, app.curAdj, app.setProcState));
+ COMPACT_PROCESS_MSG, app.setAdj, app.setProcState));
}
@@ -230,11 +230,8 @@
*/
@GuardedBy("mPhenotypeFlagLock")
private void updateUseCompaction() {
- String useCompactionFlag =
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_USE_COMPACTION);
- mUseCompaction = TextUtils.isEmpty(useCompactionFlag)
- ? DEFAULT_USE_COMPACTION : Boolean.parseBoolean(useCompactionFlag);
+ mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
if (mUseCompaction && !mCompactionThread.isAlive()) {
mCompactionThread.start();
mCompactionHandler = new MemCompactionHandler();
@@ -243,28 +240,11 @@
@GuardedBy("mPhenotypeFlagLock")
private void updateCompactionActions() {
- String compactAction1Flag =
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_COMPACT_ACTION_1);
- String compactAction2Flag =
- DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_COMPACT_ACTION_2);
+ int compactAction1 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_ACTION_1, DEFAULT_COMPACT_ACTION_1);
- int compactAction1 = DEFAULT_COMPACT_ACTION_1;
- try {
- compactAction1 = TextUtils.isEmpty(compactAction1Flag)
- ? DEFAULT_COMPACT_ACTION_1 : Integer.parseInt(compactAction1Flag);
- } catch (NumberFormatException e) {
- // Do nothing, leave default.
- }
-
- int compactAction2 = DEFAULT_COMPACT_ACTION_2;
- try {
- compactAction2 = TextUtils.isEmpty(compactAction2Flag)
- ? DEFAULT_COMPACT_ACTION_2 : Integer.parseInt(compactAction2Flag);
- } catch (NumberFormatException e) {
- // Do nothing, leave default.
- }
+ int compactAction2 = DeviceConfig.getInt(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_ACTION_2, DEFAULT_COMPACT_ACTION_2);
mCompactActionSome = compactActionIntToString(compactAction1);
mCompactActionFull = compactActionIntToString(compactAction2);
@@ -312,14 +292,8 @@
@GuardedBy("mPhenotypeFlagLock")
private void updateStatsdSampleRate() {
- String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
- KEY_COMPACT_STATSD_SAMPLE_RATE);
- try {
- mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag)
- ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag);
- } catch (NumberFormatException e) {
- mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
- }
+ mStatsdSampleRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_STATSD_SAMPLE_RATE, DEFAULT_STATSD_SAMPLE_RATE);
mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
}
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index 09df7e20..d8d6528 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -24,6 +24,7 @@
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
+import android.app.IActivityTaskManager;
import android.app.IAssistDataReceiver;
import android.content.Context;
import android.graphics.Bitmap;
@@ -33,6 +34,7 @@
import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import java.io.PrintWriter;
@@ -50,6 +52,8 @@
public static final String KEY_RECEIVER_EXTRA_INDEX = "index";
private IWindowManager mWindowManager;
+ @VisibleForTesting
+ public IActivityTaskManager mActivityTaskManager;
private Context mContext;
private AppOpsManager mAppOpsManager;
@@ -128,6 +132,7 @@
mCallbacks = callbacks;
mCallbacksLock = callbacksLock;
mWindowManager = windowManager;
+ mActivityTaskManager = ActivityTaskManager.getService();
mContext = context;
mAppOpsManager = appOpsManager;
mRequestStructureAppOps = requestStructureAppOps;
@@ -195,8 +200,7 @@
// Ensure that the current activity supports assist data
boolean isAssistDataAllowed = false;
try {
- isAssistDataAllowed =
- ActivityTaskManager.getService().isAssistDataAllowedOnCurrentActivity();
+ isAssistDataAllowed = mActivityTaskManager.isAssistDataAllowedOnCurrentActivity();
} catch (RemoteException e) {
// Should never happen
}
@@ -222,9 +226,9 @@
receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
boolean result = requestAutofillData
- ? ActivityTaskManager.getService().requestAutofillData(this,
+ ? mActivityTaskManager.requestAutofillData(this,
receiverExtras, topActivity, 0 /* flags */)
- : ActivityTaskManager.getService().requestAssistContextExtras(
+ : mActivityTaskManager.requestAssistContextExtras(
ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
/* focused= */ i == 0, /* newSessionId= */ i == 0);
if (result) {
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index af1031e..a1c941e 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -192,6 +192,9 @@
if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
sb.append("LACT ");
}
+ if ((flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0) {
+ sb.append("SLTA ");
+ }
if ((flags&Context.BIND_VISIBLE) != 0) {
sb.append("VIS ");
}
diff --git a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
index c2f1890..1c916e9 100644
--- a/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
+++ b/services/core/java/com/android/server/am/HealthStatsBatteryStatsWriter.java
@@ -17,7 +17,7 @@
package com.android.server.am;
import android.os.BatteryStats;
-import static android.os.BatteryStats.STATS_SINCE_UNPLUGGED;
+import static android.os.BatteryStats.STATS_SINCE_CHARGED;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.health.HealthKeys;
@@ -63,20 +63,20 @@
// MEASUREMENT_REALTIME_BATTERY_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_BATTERY_MS,
- bs.computeBatteryRealtime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ bs.computeBatteryRealtime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_UPTIME_BATTERY_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_BATTERY_MS,
- bs.computeBatteryUptime(mNowUptimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ bs.computeBatteryUptime(mNowUptimeMs*1000, STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_REALTIME_SCREEN_OFF_BATTERY_MS,
bs.computeBatteryScreenOffRealtime(
- mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_UPTIME_SCREEN_OFF_BATTERY_MS,
- bs.computeBatteryScreenOffUptime(mNowUptimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ bs.computeBatteryScreenOffUptime(mNowUptimeMs*1000, STATS_SINCE_CHARGED)/1000);
//
// Now on to the real per-uid stats...
@@ -161,75 +161,75 @@
if (controller != null) {
// MEASUREMENT_WIFI_IDLE_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_IDLE_MS,
- controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
// MEASUREMENT_WIFI_RX_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_MS,
- controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getRxTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
// MEASUREMENT_WIFI_TX_MS
sum = 0;
for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
- sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+ sum += counter.getCountLocked(STATS_SINCE_CHARGED);
}
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_MS, sum);
// MEASUREMENT_WIFI_POWER_MAMS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_POWER_MAMS,
- controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getPowerCounter().getCountLocked(STATS_SINCE_CHARGED));
}
controller = uid.getBluetoothControllerActivity();
if (controller != null) {
// MEASUREMENT_BLUETOOTH_IDLE_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_IDLE_MS,
- controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
// MEASUREMENT_BLUETOOTH_RX_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_MS,
- controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getRxTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
// MEASUREMENT_BLUETOOTH_TX_MS
sum = 0;
for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
- sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+ sum += counter.getCountLocked(STATS_SINCE_CHARGED);
}
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_MS, sum);
// MEASUREMENT_BLUETOOTH_POWER_MAMS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_POWER_MAMS,
- controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getPowerCounter().getCountLocked(STATS_SINCE_CHARGED));
}
controller = uid.getModemControllerActivity();
if (controller != null) {
// MEASUREMENT_MOBILE_IDLE_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_IDLE_MS,
- controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getIdleTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
// MEASUREMENT_MOBILE_RX_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_MS,
- controller.getRxTimeCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getRxTimeCounter().getCountLocked(STATS_SINCE_CHARGED));
// MEASUREMENT_MOBILE_TX_MS
sum = 0;
for (final BatteryStats.LongCounter counter: controller.getTxTimeCounters()) {
- sum += counter.getCountLocked(STATS_SINCE_UNPLUGGED);
+ sum += counter.getCountLocked(STATS_SINCE_CHARGED);
}
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_MS, sum);
// MEASUREMENT_MOBILE_POWER_MAMS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_POWER_MAMS,
- controller.getPowerCounter().getCountLocked(STATS_SINCE_UNPLUGGED));
+ controller.getPowerCounter().getCountLocked(STATS_SINCE_CHARGED));
}
// MEASUREMENT_WIFI_RUNNING_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RUNNING_MS,
- uid.getWifiRunningTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ uid.getWifiRunningTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_WIFI_FULL_LOCK_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_FULL_LOCK_MS,
- uid.getFullWifiLockTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ uid.getFullWifiLockTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
// TIMER_WIFI_SCAN
uidWriter.addTimer(UidHealthStats.TIMER_WIFI_SCAN,
- uid.getWifiScanCount(STATS_SINCE_UNPLUGGED),
- uid.getWifiScanTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ uid.getWifiScanCount(STATS_SINCE_CHARGED),
+ uid.getWifiScanTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_WIFI_MULTICAST_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_MULTICAST_MS,
- uid.getWifiMulticastTime(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED)/1000);
+ uid.getWifiMulticastTime(mNowRealtimeMs*1000, STATS_SINCE_CHARGED)/1000);
// TIMER_AUDIO
addTimer(uidWriter, UidHealthStats.TIMER_AUDIO, uid.getAudioTurnedOnTimer());
@@ -280,90 +280,90 @@
// MEASUREMENT_OTHER_USER_ACTIVITY_COUNT
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_OTHER_USER_ACTIVITY_COUNT,
uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_OTHER,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BUTTON_USER_ACTIVITY_COUNT,
uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_BUTTON,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT,
uid.getUserActivityCount(PowerManager.USER_ACTIVITY_EVENT_TOUCH,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_MOBILE_RX_BYTES
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_BYTES,
uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_MOBILE_TX_BYTES
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_BYTES,
uid.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_WIFI_RX_BYTES
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_BYTES,
uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_WIFI_TX_BYTES
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_BYTES,
uid.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_BLUETOOTH_RX_BYTES
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_BYTES,
uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_RX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_BLUETOOTH_TX_BYTES
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_BYTES,
uid.getNetworkActivityBytes(BatteryStats.NETWORK_BT_TX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_MOBILE_RX_PACKETS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS,
uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_MOBILE_TX_PACKETS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_MOBILE_TX_PACKETS,
uid.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_WIFI_RX_PACKETS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_RX_PACKETS,
uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_WIFI_TX_PACKETS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_WIFI_TX_PACKETS,
uid.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_BLUETOOTH_RX_PACKETS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_RX_PACKETS,
uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_RX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// MEASUREMENT_BLUETOOTH_TX_PACKETS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_BLUETOOTH_TX_PACKETS,
uid.getNetworkActivityPackets(BatteryStats.NETWORK_BT_TX_DATA,
- STATS_SINCE_UNPLUGGED));
+ STATS_SINCE_CHARGED));
// TIMER_MOBILE_RADIO_ACTIVE
uidWriter.addTimer(UidHealthStats.TIMER_MOBILE_RADIO_ACTIVE,
- uid.getMobileRadioActiveCount(STATS_SINCE_UNPLUGGED),
- uid.getMobileRadioActiveTime(STATS_SINCE_UNPLUGGED));
+ uid.getMobileRadioActiveCount(STATS_SINCE_CHARGED),
+ uid.getMobileRadioActiveTime(STATS_SINCE_CHARGED));
// MEASUREMENT_USER_CPU_TIME_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_USER_CPU_TIME_MS,
- uid.getUserCpuTimeUs(STATS_SINCE_UNPLUGGED)/1000);
+ uid.getUserCpuTimeUs(STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_SYSTEM_CPU_TIME_MS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_SYSTEM_CPU_TIME_MS,
- uid.getSystemCpuTimeUs(STATS_SINCE_UNPLUGGED)/1000);
+ uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED)/1000);
// MEASUREMENT_CPU_POWER_MAMS
uidWriter.addMeasurement(UidHealthStats.MEASUREMENT_CPU_POWER_MAMS, 0);
@@ -393,27 +393,27 @@
public void writeProc(HealthStatsWriter procWriter, BatteryStats.Uid.Proc proc) {
// MEASUREMENT_USER_TIME_MS
procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_USER_TIME_MS,
- proc.getUserTime(STATS_SINCE_UNPLUGGED));
+ proc.getUserTime(STATS_SINCE_CHARGED));
// MEASUREMENT_SYSTEM_TIME_MS
procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_SYSTEM_TIME_MS,
- proc.getSystemTime(STATS_SINCE_UNPLUGGED));
+ proc.getSystemTime(STATS_SINCE_CHARGED));
// MEASUREMENT_STARTS_COUNT
procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_STARTS_COUNT,
- proc.getStarts(STATS_SINCE_UNPLUGGED));
+ proc.getStarts(STATS_SINCE_CHARGED));
// MEASUREMENT_CRASHES_COUNT
procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_CRASHES_COUNT,
- proc.getNumCrashes(STATS_SINCE_UNPLUGGED));
+ proc.getNumCrashes(STATS_SINCE_CHARGED));
// MEASUREMENT_ANR_COUNT
procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_ANR_COUNT,
- proc.getNumAnrs(STATS_SINCE_UNPLUGGED));
+ proc.getNumAnrs(STATS_SINCE_CHARGED));
// MEASUREMENT_FOREGROUND_MS
procWriter.addMeasurement(ProcessHealthStats.MEASUREMENT_FOREGROUND_MS,
- proc.getForegroundTime(STATS_SINCE_UNPLUGGED));
+ proc.getForegroundTime(STATS_SINCE_CHARGED));
}
/**
@@ -434,7 +434,7 @@
final BatteryStats.Counter counter = entry.getValue();
if (counter != null) {
pkgWriter.addMeasurements(PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT,
- entry.getKey(), counter.getCountLocked(STATS_SINCE_UNPLUGGED));
+ entry.getKey(), counter.getCountLocked(STATS_SINCE_CHARGED));
}
}
}
@@ -445,11 +445,11 @@
public void writeServ(HealthStatsWriter servWriter, BatteryStats.Uid.Pkg.Serv serv) {
// MEASUREMENT_START_SERVICE_COUNT
servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_START_SERVICE_COUNT,
- serv.getStarts(STATS_SINCE_UNPLUGGED));
+ serv.getStarts(STATS_SINCE_CHARGED));
// MEASUREMENT_LAUNCH_COUNT
servWriter.addMeasurement(ServiceHealthStats.MEASUREMENT_LAUNCH_COUNT,
- serv.getLaunches(STATS_SINCE_UNPLUGGED));
+ serv.getLaunches(STATS_SINCE_CHARGED));
}
/**
@@ -457,8 +457,8 @@
*/
private void addTimer(HealthStatsWriter writer, int key, BatteryStats.Timer timer) {
if (timer != null) {
- writer.addTimer(key, timer.getCountLocked(STATS_SINCE_UNPLUGGED),
- timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED) / 1000);
+ writer.addTimer(key, timer.getCountLocked(STATS_SINCE_CHARGED),
+ timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_CHARGED) / 1000);
}
}
@@ -468,8 +468,8 @@
private void addTimers(HealthStatsWriter writer, int key, String name,
BatteryStats.Timer timer) {
if (timer != null) {
- writer.addTimers(key, name, new TimerStat(timer.getCountLocked(STATS_SINCE_UNPLUGGED),
- timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_UNPLUGGED) / 1000));
+ writer.addTimers(key, name, new TimerStat(timer.getCountLocked(STATS_SINCE_CHARGED),
+ timer.getTotalTimeLocked(mNowRealtimeMs*1000, STATS_SINCE_CHARGED) / 1000));
}
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 4e03b72..aa03de1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -38,7 +38,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
-import static com.android.server.am.ActivityManagerService.DISPATCH_PROCESSES_CHANGED_UI_MSG;
import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
import static com.android.server.am.ActivityManagerService.TAG_LRU;
@@ -1294,6 +1293,11 @@
ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
}
}
+ if (schedGroup < ProcessList.SCHED_GROUP_TOP_APP
+ && (cr.flags & Context.BIND_SCHEDULE_LIKE_TOP_APP) != 0) {
+ schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
+ }
+
if (!trackedProcState) {
cr.trackProcState(clientProcState, mAdjSeq, now);
}
@@ -1916,41 +1920,9 @@
if (changes != 0) {
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Changes in " + app + ": " + changes);
- int i = mService.mPendingProcessChanges.size()-1;
- ActivityManagerService.ProcessChangeItem item = null;
- while (i >= 0) {
- item = mService.mPendingProcessChanges.get(i);
- if (item.pid == app.pid) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Re-using existing item: " + item);
- break;
- }
- i--;
- }
- if (i < 0) {
- // No existing item in pending changes; need a new one.
- final int NA = mService.mAvailProcessChanges.size();
- if (NA > 0) {
- item = mService.mAvailProcessChanges.remove(NA-1);
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Retrieving available item: " + item);
- } else {
- item = new ActivityManagerService.ProcessChangeItem();
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "Allocating new item: " + item);
- }
- item.changes = 0;
- item.pid = app.pid;
- item.uid = app.info.uid;
- if (mService.mPendingProcessChanges.size() == 0) {
- if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
- "*** Enqueueing dispatch processes changed!");
- mService.mUiHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED_UI_MSG)
- .sendToTarget();
- }
- mService.mPendingProcessChanges.add(item);
- }
- item.changes |= changes;
+ ActivityManagerService.ProcessChangeItem item =
+ mService.enqueueProcessChangeItemLocked(app.pid, app.info.uid);
+ item.changes = changes;
item.foregroundActivities = app.repForegroundActivities;
if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
"Item " + Integer.toHexString(System.identityHashCode(item))
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 51b1ae1..17b244c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -174,6 +174,7 @@
boolean hasStartedServices; // Are there any started services running in this process?
private boolean mHasForegroundServices; // Running any services that are foreground?
private int mFgServiceTypes; // Type of foreground service, if there is a foreground service.
+ private int mRepFgServiceTypes; // Last reported foreground service types.
private boolean mHasForegroundActivities; // Running any activities that are foreground?
boolean repForegroundActivities; // Last reported foreground activities.
boolean systemNoUi; // This is a system process, but not currently showing UI.
@@ -1079,6 +1080,18 @@
&& (mFgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
}
+ int getForegroundServiceTypes() {
+ return mHasForegroundServices ? mFgServiceTypes : 0;
+ }
+
+ int getReportedForegroundServiceTypes() {
+ return mRepFgServiceTypes;
+ }
+
+ void setReportedForegroundServiceTypes(int foregroundServiceTypes) {
+ mRepFgServiceTypes = foregroundServiceTypes;
+ }
+
void setHasForegroundActivities(boolean hasForegroundActivities) {
mHasForegroundActivities = hasForegroundActivities;
mWindowProcessController.setHasForegroundActivities(hasForegroundActivities);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 029c3fb..07c9cca 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -389,14 +389,14 @@
* Step from {@link UserState#STATE_RUNNING_LOCKED} to
* {@link UserState#STATE_RUNNING_UNLOCKING}.
*/
- private void finishUserUnlocking(final UserState uss) {
+ private boolean finishUserUnlocking(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
// Only keep marching forward if user is actually unlocked
- if (!StorageManager.isUserKeyUnlocked(userId)) return;
+ if (!StorageManager.isUserKeyUnlocked(userId)) return false;
synchronized (mLock) {
// Do not proceed if unexpected state or a stale user
if (mStartedUsers.get(userId) != uss || uss.state != STATE_RUNNING_LOCKED) {
- return;
+ return false;
}
}
uss.mUnlockProgress.start();
@@ -427,6 +427,7 @@
mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
.sendToTarget();
});
+ return true;
}
/**
@@ -1209,7 +1210,10 @@
return false;
}
- finishUserUnlocking(uss);
+ if (!finishUserUnlocking(uss)) {
+ notifyFinished(userId, listener);
+ return false;
+ }
// We just unlocked a user, so let's now attempt to unlock any
// managed profiles under that user.
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 9c26526..10b67c1 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1132,7 +1132,7 @@
.build();
Preconditions.checkNotNull(callback, "callback cannot be null");
- mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+ mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
final String[] opNamesArray = (opNames != null)
@@ -1144,6 +1144,14 @@
}
@Override
+ public void reloadNonHistoricalState() {
+ mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
+ Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
+ writeState();
+ readState();
+ }
+
+ @Override
public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
@@ -2998,6 +3006,7 @@
final LongSparseArray keys = op.collectKeys();
if (keys == null || keys.size() <= 0) {
+ out.endTag(null, "op");
continue;
}
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 7da848c..31ba0f2 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -19,6 +19,7 @@
import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
@@ -59,6 +60,7 @@
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
+import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
@@ -103,6 +105,7 @@
@Override
public void onStart() {
+ publishBinderService(Context.ATTENTION_SERVICE, new BinderService());
publishLocalService(AttentionManagerInternal.class, new LocalService());
}
@@ -111,6 +114,11 @@
cancelAndUnbindLocked(peekUserStateLocked(userId));
}
+ /** Returns {@code true} if attention service is configured on this device. */
+ public static boolean isServiceConfigured(Context context) {
+ return !TextUtils.isEmpty(getServiceConfig(context));
+ }
+
/** Resolves and sets up the attention service if it had not been done yet. */
private boolean isServiceAvailable() {
if (mComponentName == null) {
@@ -283,6 +291,10 @@
return mUserStates.get(userId);
}
+ private static String getServiceConfig(Context context) {
+ return context.getString(R.string.config_defaultAttentionService);
+ }
+
/**
* Provides attention service component name at runtime, making sure it's provided by the
* system.
@@ -291,9 +303,7 @@
final String flag = DeviceConfig.getProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
COMPONENT_NAME);
- final String componentNameString = flag != null ? flag : context.getString(
- R.string.config_defaultAttentionService);
-
+ final String componentNameString = flag != null ? flag : getServiceConfig(context);
if (TextUtils.isEmpty(componentNameString)) {
return null;
}
@@ -329,17 +339,15 @@
return null;
}
- private void dumpInternal(PrintWriter pw) {
- if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
- IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
- ipw.println("Attention Manager Service (dumpsys attention)\n");
+ private void dumpInternal(IndentingPrintWriter ipw) {
+ ipw.println("Attention Manager Service (dumpsys attention) state:\n");
ipw.printPair("context", mContext);
- pw.println();
+ ipw.println();
synchronized (mLock) {
int size = mUserStates.size();
ipw.print("Number user states: ");
- pw.println(size);
+ ipw.println(size);
if (size > 0) {
ipw.increaseIndent();
for (int i = 0; i < size; i++) {
@@ -553,8 +561,8 @@
}
}
- private void cancel(UserState userState, @AttentionFailureCodes int failureCode) {
- if (userState != null && userState.mService != null) {
+ private void cancel(@NonNull UserState userState, @AttentionFailureCodes int failureCode) {
+ if (userState.mService != null) {
try {
userState.mService.cancelAttentionCheck(
userState.mCurrentAttentionCheckRequestCode);
@@ -571,6 +579,9 @@
@GuardedBy("mLock")
private void cancelAndUnbindLocked(UserState userState) {
synchronized (mLock) {
+ if (userState == null) {
+ return;
+ }
cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN);
mContext.unbindService(userState.mConnection);
@@ -591,4 +602,15 @@
}
}
}
+
+ private final class BinderService extends Binder {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) {
+ return;
+ }
+
+ dumpInternal(new IndentingPrintWriter(pw, " "));
+ }
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 69a9e7e..b774647 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -170,8 +170,15 @@
}
}
- /*package*/ void setSpeakerphoneOn(boolean on, String eventSource) {
+ /**
+ * Turns speakerphone on/off
+ * @param on
+ * @param eventSource for logging purposes
+ * @return true if speakerphone state changed
+ */
+ /*package*/ boolean setSpeakerphoneOn(boolean on, String eventSource) {
synchronized (mDeviceStateLock) {
+ final boolean wasOn = isSpeakerphoneOn();
if (on) {
if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
setForceUse_Async(AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
@@ -183,6 +190,7 @@
mForcedUseForCommExt = mForcedUseForComm;
setForceUse_Async(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource);
+ return (wasOn != isSpeakerphoneOn());
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 435fa88..a14a638 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3331,7 +3331,11 @@
final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
.append(") from u/pid:").append(Binder.getCallingUid()).append("/")
.append(Binder.getCallingPid()).toString();
- mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+ final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
+ if (stateChanged) {
+ mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+ .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
+ }
}
/** @see AudioManager#isSpeakerphoneOn() */
@@ -5953,6 +5957,14 @@
pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
pw.print(" mAvrcpAbsVolSupported=");
pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported());
+ pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume);
+ pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume);
+ pw.print(" mFixedVolumeDevices=0x"); pw.println(Integer.toHexString(mFixedVolumeDevices));
+ pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink);
+ pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
+ pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
+ pw.print(" mHdmiTvClient="); pw.println(mHdmiTvClient);
+ pw.print(" mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported);
dumpAudioPolicies(pw);
mDynPolicyLogger.dump(pw);
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index b4bbbc7..d028e88 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -543,16 +543,17 @@
}
/**
- * Called synchronized on mAudioFocusLock
+ * Called synchronized on mAudioFocusLock.
+ * Can only be called with an external focus policy installed (mFocusPolicy != null)
* @param afi
- * @param requestResult
- * @return true if the external audio focus policy (if any) is handling the focus request
+ * @param fd
+ * @param cb binder of the focus requester
+ * @return true if the external audio focus policy (if any) can handle the focus request,
+ * and false if there was any error handling the request (e.g. error talking to policy,
+ * focus requester is already dead)
*/
boolean notifyExtFocusPolicyFocusRequest_syncAf(AudioFocusInfo afi,
- IAudioFocusDispatcher fd, IBinder cb) {
- if (mFocusPolicy == null) {
- return false;
- }
+ IAudioFocusDispatcher fd, @NonNull IBinder cb) {
if (DEBUG) {
Log.v(TAG, "notifyExtFocusPolicyFocusRequest client="+afi.getClientId()
+ " dispatcher=" + fd);
@@ -561,19 +562,28 @@
afi.setGen(mExtFocusChangeCounter++);
}
final FocusRequester existingFr = mFocusOwnersForFocusPolicy.get(afi.getClientId());
+ boolean keepTrack = false;
if (existingFr != null) {
if (!existingFr.hasSameDispatcher(fd)) {
existingFr.release();
- final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
- mFocusOwnersForFocusPolicy.put(afi.getClientId(),
- new FocusRequester(afi, fd, cb, hdlr, this));
+ keepTrack = true;
}
} else {
- // new focus (future) focus owner to keep track of
+ keepTrack = true;
+ }
+ if (keepTrack) {
final AudioFocusDeathHandler hdlr = new AudioFocusDeathHandler(cb);
+ try {
+ cb.linkToDeath(hdlr, 0);
+ } catch (RemoteException e) {
+ // client has already died!
+ return false;
+ }
+ // new focus (future) focus owner to keep track of
mFocusOwnersForFocusPolicy.put(afi.getClientId(),
new FocusRequester(afi, fd, cb, hdlr, this));
}
+
try {
//oneway
mFocusPolicy.notifyAudioFocusRequest(afi, AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -600,7 +610,6 @@
/**
* Called synchronized on mAudioFocusLock
* @param afi
- * @param requestResult
* @return true if the external audio focus policy (if any) is handling the focus request
*/
boolean notifyExtFocusPolicyFocusAbandon_syncAf(AudioFocusInfo afi) {
@@ -767,10 +776,15 @@
}
// external focus policy?
- if (notifyExtFocusPolicyFocusRequest_syncAf(
- afiForExtPolicy, fd, cb)) {
- // stop handling focus request here as it is handled by external audio focus policy
- return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
+ if (mFocusPolicy != null) {
+ if (notifyExtFocusPolicyFocusRequest_syncAf(afiForExtPolicy, fd, cb)) {
+ // stop handling focus request here as it is handled by external audio
+ // focus policy (return code will be handled in AudioManager)
+ return AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY;
+ } else {
+ // an error occured, client already dead, bail early
+ return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
+ }
}
// handle the potential premature death of the new holder of the focus
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index ddd416e..516844d 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -57,6 +57,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -68,6 +69,7 @@
import android.util.StatsLog;
import com.android.internal.R;
+import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBarService;
import com.android.server.SystemService;
@@ -85,22 +87,137 @@
private static final String TAG = "BiometricService";
+ private static final int MSG_ON_TASK_STACK_CHANGED = 1;
+ private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
+ private static final int MSG_ON_AUTHENTICATION_FAILED = 3;
+ private static final int MSG_ON_ERROR = 4;
+ private static final int MSG_ON_ACQUIRED = 5;
+ private static final int MSG_ON_DISMISSED = 6;
+ private static final int MSG_ON_TRY_AGAIN_PRESSED = 7;
+ private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8;
+ private static final int MSG_AUTHENTICATE = 9;
+ private static final int MSG_CANCEL_AUTHENTICATION = 10;
+
private static final int[] FEATURE_ID = {
TYPE_FINGERPRINT,
TYPE_IRIS,
TYPE_FACE
};
+ /**
+ * Authentication either just called and we have not transitioned to the CALLED state, or
+ * authentication terminated (success or error).
+ */
+ private static final int STATE_AUTH_IDLE = 0;
+ /**
+ * Authentication was called and we are waiting for the <Biometric>Services to return their
+ * cookies before starting the hardware and showing the BiometricPrompt.
+ */
+ private static final int STATE_AUTH_CALLED = 1;
+ /**
+ * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
+ */
+ private static final int STATE_AUTH_STARTED = 2;
+ /**
+ * Authentication is paused, waiting for the user to press "try again" button. Only
+ * passive modalities such as Face or Iris should have this state. Note that for passive
+ * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
+ * fingerprint.
+ */
+ private static final int STATE_AUTH_PAUSED = 3;
+ /**
+ * Authentication is successful, but we're waiting for the user to press "confirm" button.
+ */
+ private static final int STATE_AUTH_PENDING_CONFIRM = 5;
+
+ private final class AuthSession {
+ // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
+ // <Biometric>Services before we can start authenticating. Pairs that have been returned
+ // are moved to mModalitiesMatched.
+ final HashMap<Integer, Integer> mModalitiesWaiting;
+ // Pairs that have been matched.
+ final HashMap<Integer, Integer> mModalitiesMatched = new HashMap<>();
+
+ // The following variables are passed to authenticateInternal, which initiates the
+ // appropriate <Biometric>Services.
+ final IBinder mToken;
+ final long mSessionId;
+ final int mUserId;
+ // Original receiver from BiometricPrompt.
+ final IBiometricServiceReceiver mClientReceiver;
+ final String mOpPackageName;
+ // Info to be shown on BiometricDialog when all cookies are returned.
+ final Bundle mBundle;
+ final int mCallingUid;
+ final int mCallingPid;
+ final int mCallingUserId;
+ // Continue authentication with the same modality/modalities after "try again" is
+ // pressed
+ final int mModality;
+ final boolean mRequireConfirmation;
+
+ // The current state, which can be either idle, called, or started
+ private int mState = STATE_AUTH_IDLE;
+ // For explicit confirmation, do not send to keystore until the user has confirmed
+ // the authentication.
+ byte[] mTokenEscrow;
+
+ // Timestamp when hardware authentication occurred
+ private long mAuthenticatedTimeMs;
+
+ AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
+ int userId, IBiometricServiceReceiver receiver, String opPackageName,
+ Bundle bundle, int callingUid, int callingPid, int callingUserId,
+ int modality, boolean requireConfirmation) {
+ mModalitiesWaiting = modalities;
+ mToken = token;
+ mSessionId = sessionId;
+ mUserId = userId;
+ mClientReceiver = receiver;
+ mOpPackageName = opPackageName;
+ mBundle = bundle;
+ mCallingUid = callingUid;
+ mCallingPid = callingPid;
+ mCallingUserId = callingUserId;
+ mModality = modality;
+ mRequireConfirmation = requireConfirmation;
+ }
+
+ boolean isCrypto() {
+ return mSessionId != 0;
+ }
+
+ boolean containsCookie(int cookie) {
+ if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
+ return true;
+ }
+ if (mModalitiesMatched != null && mModalitiesMatched.containsValue(cookie)) {
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private final class BiometricTaskStackListener extends TaskStackListener {
+ @Override
+ public void onTaskStackChanged() {
+ mHandler.sendEmptyMessage(MSG_ON_TASK_STACK_CHANGED);
+ }
+ }
+
private final AppOpsManager mAppOps;
- private final Handler mHandler;
private final boolean mHasFeatureFingerprint;
private final boolean mHasFeatureIris;
private final boolean mHasFeatureFace;
private final SettingObserver mSettingObserver;
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
+ private final BiometricTaskStackListener mTaskStackListener = new BiometricTaskStackListener();
+ private final Random mRandom = new Random();
private IFingerprintService mFingerprintService;
private IFaceService mFaceService;
+ private IActivityTaskManager mActivityTaskManager;
+ private IStatusBarService mStatusBarService;
// Get and cache the available authenticator (manager) classes. Used since aidl doesn't support
// polymorphism :/
@@ -113,6 +230,108 @@
// should be safe.
private int mCurrentModality;
+ // The current authentication session, null if idle/done. We need to track both the current
+ // and pending sessions since errors may be sent to either.
+ private AuthSession mCurrentAuthSession;
+ private AuthSession mPendingAuthSession;
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_TASK_STACK_CHANGED: {
+ handleTaskStackChanged();
+ break;
+ }
+
+ case MSG_ON_AUTHENTICATION_SUCCEEDED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleAuthenticationSucceeded(
+ (boolean) args.arg1 /* requireConfirmation */,
+ (byte[]) args.arg2 /* token */);
+ args.recycle();
+ break;
+ }
+
+ case MSG_ON_AUTHENTICATION_FAILED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleAuthenticationFailed(
+ args.argi1 /* cookie */,
+ (boolean) args.arg1 /* requireConfirmation */);
+ args.recycle();
+ break;
+ }
+
+ case MSG_ON_ERROR: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleOnError(
+ args.argi1 /* cookie */,
+ args.argi2 /* error */,
+ (String) args.arg1 /* message */);
+ args.recycle();
+ break;
+ }
+
+ case MSG_ON_ACQUIRED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleOnAcquired(
+ args.argi1 /* acquiredInfo */,
+ (String) args.arg1 /* message */);
+ args.recycle();
+ break;
+ }
+
+ case MSG_ON_DISMISSED: {
+ handleOnDismissed(msg.arg1);
+ break;
+ }
+
+ case MSG_ON_TRY_AGAIN_PRESSED: {
+ handleOnTryAgainPressed();
+ break;
+ }
+
+ case MSG_ON_READY_FOR_AUTHENTICATION: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleOnReadyForAuthentication(
+ args.argi1 /* cookie */,
+ (boolean) args.arg1 /* requireConfirmation */,
+ args.argi2 /* userId */);
+ args.recycle();
+ break;
+ }
+
+ case MSG_AUTHENTICATE: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleAuthenticate(
+ (IBinder) args.arg1 /* token */,
+ (long) args.arg2 /* sessionId */,
+ args.argi1 /* userid */,
+ (IBiometricServiceReceiver) args.arg3 /* receiver */,
+ (String) args.arg4 /* opPackageName */,
+ (Bundle) args.arg5 /* bundle */,
+ args.argi2 /* callingUid */,
+ args.argi3 /* callingPid */,
+ args.argi4 /* callingUserId */);
+ args.recycle();
+ break;
+ }
+
+ case MSG_CANCEL_AUTHENTICATION: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleCancelAuthentication(
+ (IBinder) args.arg1 /* token */,
+ (String) args.arg2 /* opPackageName */);
+ args.recycle();
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ };
+
private final class Authenticator {
int mType;
BiometricAuthenticator mAuthenticator;
@@ -251,142 +470,62 @@
}
}
+ // Wrap the client's receiver so we can do things with the BiometricDialog first
+ private final IBiometricServiceReceiverInternal mInternalReceiver =
+ new IBiometricServiceReceiverInternal.Stub() {
+ @Override
+ public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
+ throws RemoteException {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = requireConfirmation;
+ args.arg2 = token;
+ mHandler.obtainMessage(MSG_ON_AUTHENTICATION_SUCCEEDED, args).sendToTarget();
+ }
+
+ @Override
+ public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
+ throws RemoteException {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = cookie;
+ args.arg1 = requireConfirmation;
+ mHandler.obtainMessage(MSG_ON_AUTHENTICATION_FAILED, args).sendToTarget();
+ }
+
+ @Override
+ public void onError(int cookie, int error, String message) throws RemoteException {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = cookie;
+ args.argi2 = error;
+ args.arg1 = message;
+ mHandler.obtainMessage(MSG_ON_ERROR, args).sendToTarget();
+ }
+
+ @Override
+ public void onAcquired(int acquiredInfo, String message) throws RemoteException {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = acquiredInfo;
+ args.arg1 = message;
+ mHandler.obtainMessage(MSG_ON_ACQUIRED, args).sendToTarget();
+ }
+
+ @Override
+ public void onDialogDismissed(int reason) throws RemoteException {
+ mHandler.obtainMessage(MSG_ON_DISMISSED, reason, 0 /* arg2 */).sendToTarget();
+ }
+
+ @Override
+ public void onTryAgainPressed() {
+ mHandler.sendEmptyMessage(MSG_ON_TRY_AGAIN_PRESSED);
+ }
+ };
+
+
/**
* This is just a pass-through service that wraps Fingerprint, Iris, Face services. This service
* should not carry any state. The reality is we need to keep a tiny amount of state so that
* cancelAuthentication() can go to the right place.
*/
private final class BiometricServiceWrapper extends IBiometricService.Stub {
-
- /**
- * Authentication either just called and we have not transitioned to the CALLED state, or
- * authentication terminated (success or error).
- */
- private static final int STATE_AUTH_IDLE = 0;
- /**
- * Authentication was called and we are waiting for the <Biometric>Services to return their
- * cookies before starting the hardware and showing the BiometricPrompt.
- */
- private static final int STATE_AUTH_CALLED = 1;
- /**
- * Authentication started, BiometricPrompt is showing and the hardware is authenticating.
- */
- private static final int STATE_AUTH_STARTED = 2;
- /**
- * Authentication is paused, waiting for the user to press "try again" button. Only
- * passive modalities such as Face or Iris should have this state. Note that for passive
- * modalities, the HAL enters the idle state after onAuthenticated(false) which differs from
- * fingerprint.
- */
- private static final int STATE_AUTH_PAUSED = 3;
- /**
- * Authentication is successful, but we're waiting for the user to press "confirm" button.
- */
- private static final int STATE_AUTH_PENDING_CONFIRM = 5;
-
- final class AuthSession {
- // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
- // <Biometric>Services before we can start authenticating. Pairs that have been returned
- // are moved to mModalitiesMatched.
- final HashMap<Integer, Integer> mModalitiesWaiting;
- // Pairs that have been matched.
- final HashMap<Integer, Integer> mModalitiesMatched = new HashMap<>();
-
- // The following variables are passed to authenticateInternal, which initiates the
- // appropriate <Biometric>Services.
- final IBinder mToken;
- final long mSessionId;
- final int mUserId;
- // Original receiver from BiometricPrompt.
- final IBiometricServiceReceiver mClientReceiver;
- final String mOpPackageName;
- // Info to be shown on BiometricDialog when all cookies are returned.
- final Bundle mBundle;
- final int mCallingUid;
- final int mCallingPid;
- final int mCallingUserId;
- // Continue authentication with the same modality/modalities after "try again" is
- // pressed
- final int mModality;
- final boolean mRequireConfirmation;
-
- // The current state, which can be either idle, called, or started
- private int mState = STATE_AUTH_IDLE;
- // For explicit confirmation, do not send to keystore until the user has confirmed
- // the authentication.
- byte[] mTokenEscrow;
-
- // Timestamp when hardware authentication occurred
- private long mAuthenticatedTimeMs;
-
- AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
- int userId, IBiometricServiceReceiver receiver, String opPackageName,
- Bundle bundle, int callingUid, int callingPid, int callingUserId,
- int modality, boolean requireConfirmation) {
- mModalitiesWaiting = modalities;
- mToken = token;
- mSessionId = sessionId;
- mUserId = userId;
- mClientReceiver = receiver;
- mOpPackageName = opPackageName;
- mBundle = bundle;
- mCallingUid = callingUid;
- mCallingPid = callingPid;
- mCallingUserId = callingUserId;
- mModality = modality;
- mRequireConfirmation = requireConfirmation;
- }
-
- boolean isCrypto() {
- return mSessionId != 0;
- }
-
- boolean containsCookie(int cookie) {
- if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
- return true;
- }
- if (mModalitiesMatched != null && mModalitiesMatched.containsValue(cookie)) {
- return true;
- }
- return false;
- }
- }
-
- final class BiometricTaskStackListener extends TaskStackListener {
- @Override
- public void onTaskStackChanged() {
- try {
- final List<ActivityManager.RunningTaskInfo> runningTasks =
- mActivityTaskManager.getTasks(1);
- if (!runningTasks.isEmpty()) {
- final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (mCurrentAuthSession != null
- && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
- mStatusBarService.hideBiometricDialog();
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- mCurrentAuthSession.mClientReceiver.onError(
- BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- getContext().getString(
- com.android.internal.R.string.biometric_error_canceled)
- );
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to get running tasks", e);
- }
- }
- }
-
- private final IActivityTaskManager mActivityTaskManager = getContext().getSystemService(
- ActivityTaskManager.class).getService();
- private final IStatusBarService mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
- private final BiometricTaskStackListener mTaskStackListener =
- new BiometricTaskStackListener();
- private final Random mRandom = new Random();
-
// TODO(b/123378871): Remove when moved.
// When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
// client (app) receiver. BiometricService internally launches CDCA which invokes
@@ -395,331 +534,15 @@
// to this receiver.
private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
- // The current authentication session, null if idle/done. We need to track both the current
- // and pending sessions since errors may be sent to either.
- private AuthSession mCurrentAuthSession;
- private AuthSession mPendingAuthSession;
-
- // Wrap the client's receiver so we can do things with the BiometricDialog first
- private final IBiometricServiceReceiverInternal mInternalReceiver =
- new IBiometricServiceReceiverInternal.Stub() {
- @Override
- public void onAuthenticationSucceeded(boolean requireConfirmation, byte[] token)
- throws RemoteException {
- try {
- // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
- // after user dismissed/canceled dialog).
- if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
- return;
- }
-
- if (!requireConfirmation) {
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- KeyStore.getInstance().addAuthToken(token);
- mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- } else {
- mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
- // Store the auth token and submit it to keystore after the confirmation
- // button has been pressed.
- mCurrentAuthSession.mTokenEscrow = token;
- mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM;
- }
-
- // Notify SysUI that the biometric has been authenticated. SysUI already knows
- // the implicit/explicit state and will react accordingly.
- mStatusBarService.onBiometricAuthenticated(true);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
-
- @Override
- public void onAuthenticationFailed(int cookie, boolean requireConfirmation)
- throws RemoteException {
- try {
- // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
- // after user dismissed/canceled dialog).
- if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
- return;
- }
-
- mStatusBarService.onBiometricAuthenticated(false);
-
- // TODO: This logic will need to be updated if BP is multi-modal
- if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
- // Pause authentication. onBiometricAuthenticated(false) causes the
- // dialog to show a "try again" button for passive modalities.
- mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
- }
-
- mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
-
- @Override
- public void onError(int cookie, int error, String message) throws RemoteException {
- Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
- // Errors can either be from the current auth session or the pending auth session.
- // The pending auth session may receive errors such as ERROR_LOCKOUT before
- // it becomes the current auth session. Similarly, the current auth session may
- // receive errors such as ERROR_CANCELED while the pending auth session is preparing
- // to be started. Thus we must match error messages with their cookies to be sure
- // of their intended receivers.
- try {
- if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
- if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
- mStatusBarService.onBiometricError(message);
- if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mClientReceiver.onError(error, message);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- mStatusBarService.hideBiometricDialog();
- } else {
- // Send errors after the dialog is dismissed.
- mHandler.postDelayed(() -> {
- try {
- if (mCurrentAuthSession != null) {
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mClientReceiver.onError(error,
- message);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }, BiometricPrompt.HIDE_DIALOG_DELAY);
- }
- } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
- // In the "try again" state, we should forward canceled errors to
- // the client and and clean up.
- mCurrentAuthSession.mClientReceiver.onError(error, message);
- mStatusBarService.onBiometricError(message);
- mActivityTaskManager.unregisterTaskStackListener(
- mTaskStackListener);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- } else {
- Slog.e(TAG, "Impossible session error state: "
- + mCurrentAuthSession.mState);
- }
- } else if (mPendingAuthSession != null
- && mPendingAuthSession.containsCookie(cookie)) {
- if (mPendingAuthSession.mState == STATE_AUTH_CALLED) {
- mPendingAuthSession.mClientReceiver.onError(error, message);
- mPendingAuthSession.mState = STATE_AUTH_IDLE;
- mPendingAuthSession = null;
- } else {
- Slog.e(TAG, "Impossible pending session error state: "
- + mPendingAuthSession.mState);
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
-
- @Override
- public void onAcquired(int acquiredInfo, String message) throws RemoteException {
- // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
- // after user dismissed/canceled dialog).
- if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onAcquired(): Auth session is null");
- return;
- }
-
- if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
- try {
- mStatusBarService.onBiometricHelp(message);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
- }
-
- @Override
- public void onDialogDismissed(int reason) throws RemoteException {
- if (mCurrentAuthSession == null) {
- Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
- return;
- }
-
- logDialogDismissed(reason);
-
- if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
- // Positive button is used by passive modalities as a "confirm" button,
- // do not send to client
- mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
- // Cancel authentication. Skip the token/package check since we are cancelling
- // from system server. The interface is permission protected so this is fine.
- cancelInternal(null /* token */, null /* package */, false /* fromClient */);
- }
- if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
- mCurrentAuthSession.mClientReceiver.onError(
- BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
- getContext().getString(
- com.android.internal.R.string.biometric_error_user_canceled));
- } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
- // Have the service send the token to KeyStore, and send onAuthenticated
- // to the application
- KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
- mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
- }
- mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- }
-
- @Override
- public void onTryAgainPressed() {
- Slog.d(TAG, "onTryAgainPressed");
- // No need to check permission, since it can only be invoked by SystemUI
- // (or system server itself).
- mHandler.post(() -> {
- authenticateInternal(mCurrentAuthSession.mToken,
- mCurrentAuthSession.mSessionId,
- mCurrentAuthSession.mUserId,
- mCurrentAuthSession.mClientReceiver,
- mCurrentAuthSession.mOpPackageName,
- mCurrentAuthSession.mBundle,
- mCurrentAuthSession.mCallingUid,
- mCurrentAuthSession.mCallingPid,
- mCurrentAuthSession.mCallingUserId,
- mCurrentAuthSession.mModality);
- });
- }
-
- private void logDialogDismissed(int reason) {
- if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
- // Explicit auth, authentication confirmed.
- // Latency in this case is authenticated -> confirmed. <Biometric>Service
- // should have the first half (first acquired -> authenticated).
- final long latency = System.currentTimeMillis()
- - mCurrentAuthSession.mAuthenticatedTimeMs;
-
- if (LoggableMonitor.DEBUG) {
- Slog.v(LoggableMonitor.TAG, "Confirmed! Modality: " + statsModality()
- + ", User: " + mCurrentAuthSession.mUserId
- + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
- + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
- + ", RequireConfirmation: "
- + mCurrentAuthSession.mRequireConfirmation
- + ", State: " + StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED
- + ", Latency: " + latency);
- }
-
- StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
- statsModality(),
- mCurrentAuthSession.mUserId,
- mCurrentAuthSession.isCrypto(),
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
- mCurrentAuthSession.mRequireConfirmation,
- StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
- latency);
- } else {
- int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
- ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
- : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
- ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
- : 0;
- if (LoggableMonitor.DEBUG) {
- Slog.v(LoggableMonitor.TAG, "Dismissed! Modality: " + statsModality()
- + ", User: " + mCurrentAuthSession.mUserId
- + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
- + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
- + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
- + ", Error: " + error);
- }
- // Auth canceled
- StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
- statsModality(),
- mCurrentAuthSession.mUserId,
- mCurrentAuthSession.isCrypto(),
- BiometricsProtoEnums.ACTION_AUTHENTICATE,
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
- error,
- 0 /* vendorCode */);
- }
- }
-
- private int statsModality() {
- int modality = 0;
- if (mCurrentAuthSession == null) {
- return BiometricsProtoEnums.MODALITY_UNKNOWN;
- }
- if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FINGERPRINT)
- != 0) {
- modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT;
- }
- if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_IRIS) != 0) {
- modality |= BiometricsProtoEnums.MODALITY_IRIS;
- }
- if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FACE) != 0) {
- modality |= BiometricsProtoEnums.MODALITY_FACE;
- }
- return modality;
- }
- };
-
@Override // Binder call
public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) {
checkInternalPermission();
- Iterator it = mPendingAuthSession.mModalitiesWaiting.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
- if (pair.getValue() == cookie) {
- mPendingAuthSession.mModalitiesMatched.put(pair.getKey(), pair.getValue());
- mPendingAuthSession.mModalitiesWaiting.remove(pair.getKey());
- Slog.d(TAG, "Matched cookie: " + cookie + ", "
- + mPendingAuthSession.mModalitiesWaiting.size() + " remaining");
- break;
- }
- }
-
- if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
- final boolean continuing = mCurrentAuthSession != null &&
- (mCurrentAuthSession.mState == STATE_AUTH_PAUSED);
-
- mCurrentAuthSession = mPendingAuthSession;
- mPendingAuthSession = null;
-
- mCurrentAuthSession.mState = STATE_AUTH_STARTED;
- try {
- int modality = TYPE_NONE;
- it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
- if (pair.getKey() == TYPE_FINGERPRINT) {
- mFingerprintService.startPreparedClient(pair.getValue());
- } else if (pair.getKey() == TYPE_IRIS) {
- Slog.e(TAG, "Iris unsupported");
- } else if (pair.getKey() == TYPE_FACE) {
- mFaceService.startPreparedClient(pair.getValue());
- } else {
- Slog.e(TAG, "Unknown modality: " + pair.getKey());
- }
- modality |= pair.getKey();
- }
-
- if (!continuing) {
- mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
- mInternalReceiver, modality, requireConfirmation, userId);
- mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- }
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = cookie;
+ args.arg1 = requireConfirmation;
+ args.argi2 = userId;
+ mHandler.obtainMessage(MSG_ON_READY_FOR_AUTHENTICATION, args).sendToTarget();
}
@Override // Binder call
@@ -754,25 +577,23 @@
checkInternalPermission();
// Set the default title if necessary
try {
- if (useDefaultTitle) {
- final List<ActivityManager.RunningAppProcessInfo> procs =
- ActivityManager.getService().getRunningAppProcesses();
- for (int i = 0; i < procs.size(); i++) {
- final ActivityManager.RunningAppProcessInfo info = procs.get(i);
- if (info.uid == callingUid
- && info.importance == IMPORTANCE_FOREGROUND) {
- PackageManager pm = getContext().getPackageManager();
- final CharSequence label = pm.getApplicationLabel(
- pm.getApplicationInfo(info.processName,
- PackageManager.GET_META_DATA));
- final String title = getContext()
- .getString(R.string.biometric_dialog_default_title, label);
- if (TextUtils.isEmpty(
- bundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
- bundle.putCharSequence(BiometricPrompt.KEY_TITLE, title);
- }
- break;
+ final List<ActivityManager.RunningAppProcessInfo> procs =
+ ActivityManager.getService().getRunningAppProcesses();
+ for (int i = 0; i < procs.size(); i++) {
+ final ActivityManager.RunningAppProcessInfo info = procs.get(i);
+ if (info.uid == callingUid
+ && info.importance == IMPORTANCE_FOREGROUND) {
+ PackageManager pm = getContext().getPackageManager();
+ final CharSequence label = pm.getApplicationLabel(
+ pm.getApplicationInfo(info.processName,
+ PackageManager.GET_META_DATA));
+ final String title = getContext()
+ .getString(R.string.biometric_dialog_default_title, label);
+ if (TextUtils.isEmpty(
+ bundle.getCharSequence(BiometricPrompt.KEY_TITLE))) {
+ bundle.putCharSequence(BiometricPrompt.KEY_TITLE, title);
}
+ break;
}
}
} catch (RemoteException e) {
@@ -792,7 +613,8 @@
KeyguardManager.class);
if (!kgm.isDeviceSecure()) {
try {
- receiver.onError(BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
+ receiver.onError(
+ BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
getContext().getString(
R.string.biometric_error_device_not_secured));
} catch (RemoteException e) {
@@ -806,165 +628,71 @@
null /* description */);
// Then give it the bundle to do magic behavior..
intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle);
+ // Create a new task with this activity located at the root.
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
getContext().startActivityAsUser(intent, UserHandle.CURRENT);
});
return;
}
- mHandler.post(() -> {
- final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
- final int modality = result.first;
- final int error = result.second;
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = token;
+ args.arg2 = sessionId;
+ args.argi1 = userId;
+ args.arg3 = receiver;
+ args.arg4 = opPackageName;
+ args.arg5 = bundle;
+ args.argi2 = callingUid;
+ args.argi3 = callingPid;
+ args.argi4 = callingUserId;
- // Check for errors, notify callback, and return
- if (error != BiometricConstants.BIOMETRIC_SUCCESS) {
- try {
- final String hardwareUnavailable =
- getContext().getString(R.string.biometric_error_hw_unavailable);
- switch (error) {
- case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
- receiver.onError(error, hardwareUnavailable);
- break;
- case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE:
- receiver.onError(error, hardwareUnavailable);
- break;
- case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS:
- receiver.onError(error,
- getErrorString(modality, error, 0 /* vendorCode */));
- break;
- default:
- Slog.e(TAG, "Unhandled error");
- break;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to send error", e);
- }
- return;
- }
-
- mCurrentModality = modality;
-
- // Start preparing for authentication. Authentication starts when
- // all modalities requested have invoked onReadyForAuthentication.
- authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
- callingUid, callingPid, callingUserId, modality);
- });
+ mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
}
@Override // Binder call
public void onConfirmDeviceCredentialSuccess() {
checkInternalPermission();
- if (mConfirmDeviceCredentialReceiver == null) {
- Slog.w(TAG, "onCDCASuccess null!");
- return;
- }
- try {
- mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- mConfirmDeviceCredentialReceiver = null;
+ mHandler.post(() -> {
+ if (mConfirmDeviceCredentialReceiver == null) {
+ Slog.w(TAG, "onCDCASuccess null!");
+ return;
+ }
+ try {
+ mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ mConfirmDeviceCredentialReceiver = null;
+ });
}
@Override // Binder call
public void onConfirmDeviceCredentialError(int error, String message) {
checkInternalPermission();
- if (mConfirmDeviceCredentialReceiver == null) {
- Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
- return;
- }
- try {
- mConfirmDeviceCredentialReceiver.onError(error, message);
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException", e);
- }
- mConfirmDeviceCredentialReceiver = null;
- }
-
- /**
- * authenticate() (above) which is called from BiometricPrompt determines which
- * modality/modalities to start authenticating with. authenticateInternal() should only be
- * used for:
- * 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is,
- * invoked, shortly after which BiometricPrompt is shown and authentication starts
- * 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown
- * and the user has pressed "try again"
- */
- private void authenticateInternal(IBinder token, long sessionId, int userId,
- IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
- int callingUid, int callingPid, int callingUserId, int modality) {
- try {
- boolean requireConfirmation = bundle.getBoolean(
- BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
- if ((modality & TYPE_FACE) != 0) {
- // Check if the user has forced confirmation to be required in Settings.
- requireConfirmation = requireConfirmation
- || mSettingObserver.getFaceAlwaysRequireConfirmation();
+ mHandler.post(() -> {
+ if (mConfirmDeviceCredentialReceiver == null) {
+ Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+ return;
}
- // Generate random cookies to pass to the services that should prepare to start
- // authenticating. Store the cookie here and wait for all services to "ack"
- // with the cookie. Once all cookies are received, we can show the prompt
- // and let the services start authenticating. The cookie should be non-zero.
- final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
- Slog.d(TAG, "Creating auth session. Modality: " + modality
- + ", cookie: " + cookie);
- final HashMap<Integer, Integer> authenticators = new HashMap<>();
- authenticators.put(modality, cookie);
- mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
- receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
- modality, requireConfirmation);
- mPendingAuthSession.mState = STATE_AUTH_CALLED;
- // No polymorphism :(
- if ((modality & TYPE_FINGERPRINT) != 0) {
- mFingerprintService.prepareForAuthentication(token, sessionId, userId,
- mInternalReceiver, opPackageName, cookie,
- callingUid, callingPid, callingUserId);
+ try {
+ mConfirmDeviceCredentialReceiver.onError(error, message);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
}
- if ((modality & TYPE_IRIS) != 0) {
- Slog.w(TAG, "Iris unsupported");
- }
- if ((modality & TYPE_FACE) != 0) {
- mFaceService.prepareForAuthentication(requireConfirmation,
- token, sessionId, userId, mInternalReceiver, opPackageName,
- cookie, callingUid, callingPid, callingUserId);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to start authentication", e);
- }
+ mConfirmDeviceCredentialReceiver = null;
+ });
}
@Override // Binder call
public void cancelAuthentication(IBinder token, String opPackageName)
throws RemoteException {
checkPermission();
- if (token == null || opPackageName == null) {
- Slog.e(TAG, "Unable to cancel, one or more null arguments");
- return;
- }
- // We need to check the current authenticators state. If we're pending confirm
- // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
- // since we won't be getting an onError from the driver.
- if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
- mHandler.post(() -> {
- try {
- // Send error to client
- mCurrentAuthSession.mClientReceiver.onError(
- BiometricConstants.BIOMETRIC_ERROR_CANCELED,
- getContext().getString(
- com.android.internal.R.string.biometric_error_user_canceled)
- );
-
- mCurrentAuthSession.mState = STATE_AUTH_IDLE;
- mCurrentAuthSession = null;
- mStatusBarService.hideBiometricDialog();
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception", e);
- }
- });
- } else {
- cancelInternal(token, opPackageName, true /* fromClient */);
- }
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = token;
+ args.arg2 = opPackageName;
+ mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget();
}
@Override // Binder call
@@ -1027,31 +755,6 @@
Binder.restoreCallingIdentity(ident);
}
}
-
- void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int callingUserId = UserHandle.getCallingUserId();
- mHandler.post(() -> {
- try {
- // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
- // drivers have canceled authentication.
- if ((mCurrentModality & TYPE_FINGERPRINT) != 0) {
- mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId, fromClient);
- }
- if ((mCurrentModality & TYPE_IRIS) != 0) {
- Slog.w(TAG, "Iris unsupported");
- }
- if ((mCurrentModality & TYPE_FACE) != 0) {
- mFaceService.cancelAuthenticationFromService(token, opPackageName,
- callingUid, callingPid, callingUserId, fromClient);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to cancel authentication");
- }
- });
- }
}
private void checkAppOp(String opPackageName, int callingUid) {
@@ -1088,7 +791,6 @@
super(context);
mAppOps = context.getSystemService(AppOpsManager.class);
- mHandler = new Handler(Looper.getMainLooper());
mEnabledOnKeyguardCallbacks = new ArrayList<>();
mSettingObserver = new SettingObserver(mHandler);
@@ -1123,6 +825,10 @@
ServiceManager.getService(Context.FACE_SERVICE));
}
+ mActivityTaskManager = ActivityTaskManager.getService();
+ mStatusBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+
// Cache the authenticators
for (int i = 0; i < FEATURE_ID.length; i++) {
if (hasFeature(FEATURE_ID[i])) {
@@ -1259,4 +965,491 @@
return false;
}
}
+
+ private void logDialogDismissed(int reason) {
+ if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ // Explicit auth, authentication confirmed.
+ // Latency in this case is authenticated -> confirmed. <Biometric>Service
+ // should have the first half (first acquired -> authenticated).
+ final long latency = System.currentTimeMillis()
+ - mCurrentAuthSession.mAuthenticatedTimeMs;
+
+ if (LoggableMonitor.DEBUG) {
+ Slog.v(LoggableMonitor.TAG, "Confirmed! Modality: " + statsModality()
+ + ", User: " + mCurrentAuthSession.mUserId
+ + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
+ + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+ + ", RequireConfirmation: "
+ + mCurrentAuthSession.mRequireConfirmation
+ + ", State: " + StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED
+ + ", Latency: " + latency);
+ }
+
+ StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
+ statsModality(),
+ mCurrentAuthSession.mUserId,
+ mCurrentAuthSession.isCrypto(),
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ mCurrentAuthSession.mRequireConfirmation,
+ StatsLog.BIOMETRIC_AUTHENTICATED__STATE__CONFIRMED,
+ latency);
+ } else {
+ int error = reason == BiometricPrompt.DISMISSED_REASON_NEGATIVE
+ ? BiometricConstants.BIOMETRIC_ERROR_NEGATIVE_BUTTON
+ : reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL
+ ? BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
+ : 0;
+ if (LoggableMonitor.DEBUG) {
+ Slog.v(LoggableMonitor.TAG, "Dismissed! Modality: " + statsModality()
+ + ", User: " + mCurrentAuthSession.mUserId
+ + ", IsCrypto: " + mCurrentAuthSession.isCrypto()
+ + ", Action: " + BiometricsProtoEnums.ACTION_AUTHENTICATE
+ + ", Client: " + BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT
+ + ", Error: " + error);
+ }
+ // Auth canceled
+ StatsLog.write(StatsLog.BIOMETRIC_ERROR_OCCURRED,
+ statsModality(),
+ mCurrentAuthSession.mUserId,
+ mCurrentAuthSession.isCrypto(),
+ BiometricsProtoEnums.ACTION_AUTHENTICATE,
+ BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ error,
+ 0 /* vendorCode */);
+ }
+ }
+
+ private int statsModality() {
+ int modality = 0;
+ if (mCurrentAuthSession == null) {
+ return BiometricsProtoEnums.MODALITY_UNKNOWN;
+ }
+ if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FINGERPRINT)
+ != 0) {
+ modality |= BiometricsProtoEnums.MODALITY_FINGERPRINT;
+ }
+ if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_IRIS) != 0) {
+ modality |= BiometricsProtoEnums.MODALITY_IRIS;
+ }
+ if ((mCurrentAuthSession.mModality & BiometricAuthenticator.TYPE_FACE) != 0) {
+ modality |= BiometricsProtoEnums.MODALITY_FACE;
+ }
+ return modality;
+ }
+
+ private void handleTaskStackChanged() {
+ try {
+ final List<ActivityManager.RunningTaskInfo> runningTasks =
+ mActivityTaskManager.getTasks(1);
+ if (!runningTasks.isEmpty()) {
+ final String topPackage = runningTasks.get(0).topActivity.getPackageName();
+ if (mCurrentAuthSession != null
+ && !topPackage.contentEquals(mCurrentAuthSession.mOpPackageName)) {
+ mStatusBarService.hideBiometricDialog();
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ mCurrentAuthSession.mClientReceiver.onError(
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ getContext().getString(
+ com.android.internal.R.string.biometric_error_canceled)
+ );
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get running tasks", e);
+ }
+ }
+
+ private void handleAuthenticationSucceeded(boolean requireConfirmation, byte[] token) {
+
+ try {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onAuthenticationSucceeded(): Auth session is null");
+ return;
+ }
+
+ if (!requireConfirmation) {
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ KeyStore.getInstance().addAuthToken(token);
+ mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ } else {
+ mCurrentAuthSession.mAuthenticatedTimeMs = System.currentTimeMillis();
+ // Store the auth token and submit it to keystore after the confirmation
+ // button has been pressed.
+ mCurrentAuthSession.mTokenEscrow = token;
+ mCurrentAuthSession.mState = STATE_AUTH_PENDING_CONFIRM;
+ }
+
+ // Notify SysUI that the biometric has been authenticated. SysUI already knows
+ // the implicit/explicit state and will react accordingly.
+ mStatusBarService.onBiometricAuthenticated(true);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ private void handleAuthenticationFailed(int cookie, boolean requireConfirmation) {
+ try {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onAuthenticationFailed(): Auth session is null");
+ return;
+ }
+
+ mStatusBarService.onBiometricAuthenticated(false);
+
+ // TODO: This logic will need to be updated if BP is multi-modal
+ if ((mCurrentAuthSession.mModality & TYPE_FACE) != 0) {
+ // Pause authentication. onBiometricAuthenticated(false) causes the
+ // dialog to show a "try again" button for passive modalities.
+ mCurrentAuthSession.mState = STATE_AUTH_PAUSED;
+ }
+
+ mCurrentAuthSession.mClientReceiver.onAuthenticationFailed();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ private void handleOnError(int cookie, int error, String message) {
+ Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
+ // Errors can either be from the current auth session or the pending auth session.
+ // The pending auth session may receive errors such as ERROR_LOCKOUT before
+ // it becomes the current auth session. Similarly, the current auth session may
+ // receive errors such as ERROR_CANCELED while the pending auth session is preparing
+ // to be started. Thus we must match error messages with their cookies to be sure
+ // of their intended receivers.
+ try {
+ if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
+ if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
+ mStatusBarService.onBiometricError(message);
+ if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
+ mActivityTaskManager.unregisterTaskStackListener(
+ mTaskStackListener);
+ mCurrentAuthSession.mClientReceiver.onError(error, message);
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ mStatusBarService.hideBiometricDialog();
+ } else {
+ // Send errors after the dialog is dismissed.
+ mHandler.postDelayed(() -> {
+ try {
+ if (mCurrentAuthSession != null) {
+ mActivityTaskManager.unregisterTaskStackListener(
+ mTaskStackListener);
+ mCurrentAuthSession.mClientReceiver.onError(error,
+ message);
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }, BiometricPrompt.HIDE_DIALOG_DELAY);
+ }
+ } else if (mCurrentAuthSession.mState == STATE_AUTH_PAUSED) {
+ // In the "try again" state, we should forward canceled errors to
+ // the client and and clean up.
+ mCurrentAuthSession.mClientReceiver.onError(error, message);
+ mStatusBarService.onBiometricError(message);
+ mActivityTaskManager.unregisterTaskStackListener(
+ mTaskStackListener);
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ } else {
+ Slog.e(TAG, "Impossible session error state: "
+ + mCurrentAuthSession.mState);
+ }
+ } else if (mPendingAuthSession != null
+ && mPendingAuthSession.containsCookie(cookie)) {
+ if (mPendingAuthSession.mState == STATE_AUTH_CALLED) {
+ mPendingAuthSession.mClientReceiver.onError(error, message);
+ mPendingAuthSession.mState = STATE_AUTH_IDLE;
+ mPendingAuthSession = null;
+ } else {
+ Slog.e(TAG, "Impossible pending session error state: "
+ + mPendingAuthSession.mState);
+ }
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ private void handleOnAcquired(int acquiredInfo, String message) {
+ // Should never happen, log this to catch bad HAL behavior (e.g. auth succeeded
+ // after user dismissed/canceled dialog).
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onAcquired(): Auth session is null");
+ return;
+ }
+
+ if (acquiredInfo != BiometricConstants.BIOMETRIC_ACQUIRED_GOOD) {
+ try {
+ mStatusBarService.onBiometricHelp(message);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ }
+
+ private void handleOnDismissed(int reason) {
+ if (mCurrentAuthSession == null) {
+ Slog.e(TAG, "onDialogDismissed: " + reason + ", auth session null");
+ return;
+ }
+
+ logDialogDismissed(reason);
+
+ try {
+ if (reason != BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ // Positive button is used by passive modalities as a "confirm" button,
+ // do not send to client
+ mCurrentAuthSession.mClientReceiver.onDialogDismissed(reason);
+ // Cancel authentication. Skip the token/package check since we are cancelling
+ // from system server. The interface is permission protected so this is fine.
+ cancelInternal(null /* token */, null /* package */, false /* fromClient */);
+ }
+ if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
+ mCurrentAuthSession.mClientReceiver.onError(
+ BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED,
+ getContext().getString(
+ com.android.internal.R.string.biometric_error_user_canceled));
+ } else if (reason == BiometricPrompt.DISMISSED_REASON_POSITIVE) {
+ // Have the service send the token to KeyStore, and send onAuthenticated
+ // to the application
+ KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
+ mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
+ }
+ mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+
+ private void handleOnTryAgainPressed() {
+ Slog.d(TAG, "onTryAgainPressed");
+ // No need to check permission, since it can only be invoked by SystemUI
+ // (or system server itself).
+ authenticateInternal(mCurrentAuthSession.mToken,
+ mCurrentAuthSession.mSessionId,
+ mCurrentAuthSession.mUserId,
+ mCurrentAuthSession.mClientReceiver,
+ mCurrentAuthSession.mOpPackageName,
+ mCurrentAuthSession.mBundle,
+ mCurrentAuthSession.mCallingUid,
+ mCurrentAuthSession.mCallingPid,
+ mCurrentAuthSession.mCallingUserId,
+ mCurrentAuthSession.mModality);
+ }
+
+ private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation,
+ int userId) {
+ Iterator it = mPendingAuthSession.mModalitiesWaiting.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
+ if (pair.getValue() == cookie) {
+ mPendingAuthSession.mModalitiesMatched.put(pair.getKey(), pair.getValue());
+ mPendingAuthSession.mModalitiesWaiting.remove(pair.getKey());
+ Slog.d(TAG, "Matched cookie: " + cookie + ", "
+ + mPendingAuthSession.mModalitiesWaiting.size() + " remaining");
+ break;
+ }
+ }
+
+ if (mPendingAuthSession.mModalitiesWaiting.isEmpty()) {
+ final boolean continuing = mCurrentAuthSession != null
+ && mCurrentAuthSession.mState == STATE_AUTH_PAUSED;
+
+ mCurrentAuthSession = mPendingAuthSession;
+ mPendingAuthSession = null;
+
+ mCurrentAuthSession.mState = STATE_AUTH_STARTED;
+ try {
+ int modality = TYPE_NONE;
+ it = mCurrentAuthSession.mModalitiesMatched.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<Integer, Integer> pair = (Map.Entry) it.next();
+ if (pair.getKey() == TYPE_FINGERPRINT) {
+ mFingerprintService.startPreparedClient(pair.getValue());
+ } else if (pair.getKey() == TYPE_IRIS) {
+ Slog.e(TAG, "Iris unsupported");
+ } else if (pair.getKey() == TYPE_FACE) {
+ mFaceService.startPreparedClient(pair.getValue());
+ } else {
+ Slog.e(TAG, "Unknown modality: " + pair.getKey());
+ }
+ modality |= pair.getKey();
+ }
+
+ if (!continuing) {
+ mStatusBarService.showBiometricDialog(mCurrentAuthSession.mBundle,
+ mInternalReceiver, modality, requireConfirmation, userId);
+ mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ }
+ }
+
+ private void handleAuthenticate(IBinder token, long sessionId, int userId,
+ IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
+ int callingUid, int callingPid, int callingUserId) {
+
+ mHandler.post(() -> {
+ final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
+ final int modality = result.first;
+ final int error = result.second;
+
+ // Check for errors, notify callback, and return
+ if (error != BiometricConstants.BIOMETRIC_SUCCESS) {
+ try {
+ final String hardwareUnavailable =
+ getContext().getString(R.string.biometric_error_hw_unavailable);
+ switch (error) {
+ case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT:
+ receiver.onError(error, hardwareUnavailable);
+ break;
+ case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE:
+ receiver.onError(error, hardwareUnavailable);
+ break;
+ case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS:
+ receiver.onError(error,
+ getErrorString(modality, error, 0 /* vendorCode */));
+ break;
+ default:
+ Slog.e(TAG, "Unhandled error");
+ break;
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to send error", e);
+ }
+ return;
+ }
+
+ mCurrentModality = modality;
+
+ // Start preparing for authentication. Authentication starts when
+ // all modalities requested have invoked onReadyForAuthentication.
+ authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
+ callingUid, callingPid, callingUserId, modality);
+ });
+ }
+
+ /**
+ * authenticate() (above) which is called from BiometricPrompt determines which
+ * modality/modalities to start authenticating with. authenticateInternal() should only be
+ * used for:
+ * 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is,
+ * invoked, shortly after which BiometricPrompt is shown and authentication starts
+ * 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown
+ * and the user has pressed "try again"
+ */
+ private void authenticateInternal(IBinder token, long sessionId, int userId,
+ IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
+ int callingUid, int callingPid, int callingUserId, int modality) {
+ try {
+ boolean requireConfirmation = bundle.getBoolean(
+ BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
+ if ((modality & TYPE_FACE) != 0) {
+ // Check if the user has forced confirmation to be required in Settings.
+ requireConfirmation = requireConfirmation
+ || mSettingObserver.getFaceAlwaysRequireConfirmation();
+ }
+ // Generate random cookies to pass to the services that should prepare to start
+ // authenticating. Store the cookie here and wait for all services to "ack"
+ // with the cookie. Once all cookies are received, we can show the prompt
+ // and let the services start authenticating. The cookie should be non-zero.
+ final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1;
+ Slog.d(TAG, "Creating auth session. Modality: " + modality
+ + ", cookie: " + cookie);
+ final HashMap<Integer, Integer> authenticators = new HashMap<>();
+ authenticators.put(modality, cookie);
+ mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
+ receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
+ modality, requireConfirmation);
+ mPendingAuthSession.mState = STATE_AUTH_CALLED;
+ // No polymorphism :(
+ if ((modality & TYPE_FINGERPRINT) != 0) {
+ mFingerprintService.prepareForAuthentication(token, sessionId, userId,
+ mInternalReceiver, opPackageName, cookie,
+ callingUid, callingPid, callingUserId);
+ }
+ if ((modality & TYPE_IRIS) != 0) {
+ Slog.w(TAG, "Iris unsupported");
+ }
+ if ((modality & TYPE_FACE) != 0) {
+ mFaceService.prepareForAuthentication(requireConfirmation,
+ token, sessionId, userId, mInternalReceiver, opPackageName,
+ cookie, callingUid, callingPid, callingUserId);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to start authentication", e);
+ }
+ }
+
+ private void handleCancelAuthentication(IBinder token, String opPackageName) {
+ if (token == null || opPackageName == null) {
+ Slog.e(TAG, "Unable to cancel, one or more null arguments");
+ return;
+ }
+
+ // We need to check the current authenticators state. If we're pending confirm
+ // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
+ // since we won't be getting an onError from the driver.
+ if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+ try {
+ // Send error to client
+ mCurrentAuthSession.mClientReceiver.onError(
+ BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+ getContext().getString(
+ com.android.internal.R.string.biometric_error_user_canceled)
+ );
+
+ mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+ mCurrentAuthSession = null;
+ mStatusBarService.hideBiometricDialog();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception", e);
+ }
+ } else {
+ cancelInternal(token, opPackageName, true /* fromClient */);
+ }
+ }
+
+
+ void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getCallingUserId();
+ mHandler.post(() -> {
+ try {
+ // TODO: For multiple modalities, send a single ERROR_CANCELED only when all
+ // drivers have canceled authentication.
+ if ((mCurrentModality & TYPE_FINGERPRINT) != 0) {
+ mFingerprintService.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId, fromClient);
+ }
+ if ((mCurrentModality & TYPE_IRIS) != 0) {
+ Slog.w(TAG, "Iris unsupported");
+ }
+ if ((mCurrentModality & TYPE_FACE) != 0) {
+ mFaceService.cancelAuthenticationFromService(token, opPackageName,
+ callingUid, callingPid, callingUserId, fromClient);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to cancel authentication");
+ }
+ });
+ }
+
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index ebb9e06..3e48445 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -1223,6 +1223,9 @@
BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
} else {
clearEnumerateState();
+ if (mPendingClient != null) {
+ startClient(mPendingClient, false /* initiatedByClient */);
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 35d6860..0e3d82c 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -42,7 +42,6 @@
import android.net.SocketKeepalive.InvalidPacketException;
import android.net.SocketKeepalive.InvalidSocketException;
import android.net.TcpKeepalivePacketData;
-import android.net.TcpKeepalivePacketData.TcpSocketInfo;
import android.net.util.IpUtils;
import android.os.Binder;
import android.os.Handler;
@@ -492,19 +491,14 @@
return;
}
- TcpKeepalivePacketData packet = null;
+ final TcpKeepalivePacketData packet;
try {
- TcpSocketInfo tsi = TcpKeepaliveController.switchToRepairMode(fd);
- packet = TcpKeepalivePacketData.tcpKeepalivePacket(tsi);
+ packet = TcpKeepaliveController.getTcpKeepalivePacket(fd);
} catch (InvalidPacketException | InvalidSocketException e) {
- try {
- TcpKeepaliveController.switchOutOfRepairMode(fd);
- } catch (ErrnoException e1) {
- Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive");
- }
notifyErrorCallback(cb, e.error);
return;
}
+
KeepaliveInfo ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
KeepaliveInfo.TYPE_TCP, fd);
Log.d(TAG, "Created keepalive: " + ki.toString());
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 053da0d..828a1e5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -28,6 +28,7 @@
import android.content.res.Resources;
import android.net.wifi.WifiInfo;
import android.os.UserHandle;
+import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Slog;
@@ -92,7 +93,7 @@
return -1;
}
- private static String getTransportName(int transportType) {
+ private static String getTransportName(@TransportType int transportType) {
Resources r = Resources.getSystem();
String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
try {
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index 3e21b5b..f4d9006 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -28,8 +28,10 @@
import android.annotation.NonNull;
import android.net.NetworkUtils;
+import android.net.SocketKeepalive.InvalidPacketException;
import android.net.SocketKeepalive.InvalidSocketException;
-import android.net.TcpKeepalivePacketData.TcpSocketInfo;
+import android.net.TcpKeepalivePacketData;
+import android.net.TcpKeepalivePacketDataParcelable;
import android.net.TcpRepairWindow;
import android.os.Handler;
import android.os.MessageQueue;
@@ -44,7 +46,6 @@
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
import java.io.FileDescriptor;
-import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
@@ -103,26 +104,30 @@
mFdHandlerQueue = connectivityServiceHandler.getLooper().getQueue();
}
+ /** Build tcp keepalive packet. */
+ public static TcpKeepalivePacketData getTcpKeepalivePacket(@NonNull FileDescriptor fd)
+ throws InvalidPacketException, InvalidSocketException {
+ try {
+ final TcpKeepalivePacketDataParcelable tcpDetails = switchToRepairMode(fd);
+ return TcpKeepalivePacketData.tcpKeepalivePacket(tcpDetails);
+ } catch (InvalidPacketException | InvalidSocketException e) {
+ switchOutOfRepairMode(fd);
+ throw e;
+ }
+ }
/**
- * Switch the tcp socket to repair mode and query tcp socket information.
+ * Switch the tcp socket to repair mode and query detail tcp information.
*
- * @param fd the fd of socket on which to use keepalive offload
- * @return a {@link TcpKeepalivePacketData#TcpSocketInfo} object for current
+ * @param fd the fd of socket on which to use keepalive offload.
+ * @return a {@link TcpKeepalivePacketData#TcpKeepalivePacketDataParcelable} object for current
* tcp/ip information.
*/
- // TODO : make this private. It's far too confusing that this gets called from outside
- // at a time that nobody can understand.
- public static TcpSocketInfo switchToRepairMode(FileDescriptor fd)
+ private static TcpKeepalivePacketDataParcelable switchToRepairMode(FileDescriptor fd)
throws InvalidSocketException {
if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
+ final TcpKeepalivePacketDataParcelable tcpDetails = new TcpKeepalivePacketDataParcelable();
final SocketAddress srcSockAddr;
final SocketAddress dstSockAddr;
- final InetAddress srcAddress;
- final InetAddress dstAddress;
- final int srcPort;
- final int dstPort;
- int seq;
- final int ack;
final TcpRepairWindow trw;
// Query source address and port.
@@ -133,8 +138,8 @@
throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
}
if (srcSockAddr instanceof InetSocketAddress) {
- srcAddress = getAddress((InetSocketAddress) srcSockAddr);
- srcPort = getPort((InetSocketAddress) srcSockAddr);
+ tcpDetails.srcAddress = getAddress((InetSocketAddress) srcSockAddr);
+ tcpDetails.srcPort = getPort((InetSocketAddress) srcSockAddr);
} else {
Log.e(TAG, "Invalid or mismatched SocketAddress");
throw new InvalidSocketException(ERROR_INVALID_SOCKET);
@@ -147,8 +152,8 @@
throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
}
if (dstSockAddr instanceof InetSocketAddress) {
- dstAddress = getAddress((InetSocketAddress) dstSockAddr);
- dstPort = getPort((InetSocketAddress) dstSockAddr);
+ tcpDetails.dstAddress = getAddress((InetSocketAddress) dstSockAddr);
+ tcpDetails.dstPort = getPort((InetSocketAddress) dstSockAddr);
} else {
Log.e(TAG, "Invalid or mismatched peer SocketAddress");
throw new InvalidSocketException(ERROR_INVALID_SOCKET);
@@ -157,28 +162,37 @@
// Query sequence and ack number
dropAllIncomingPackets(fd, true);
try {
- // Enter tcp repair mode.
+ // Switch to tcp repair mode.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_ON);
+
// Check if socket is idle.
if (!isSocketIdle(fd)) {
+ Log.e(TAG, "Socket is not idle");
throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
}
// Query write sequence number from SEND_QUEUE.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_SEND_QUEUE);
- seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ tcpDetails.seq = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
// Query read sequence number from RECV_QUEUE.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_RECV_QUEUE);
- ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
+ tcpDetails.ack = Os.getsockoptInt(fd, IPPROTO_TCP, TCP_QUEUE_SEQ);
// Switch to NO_QUEUE to prevent illegal socket read/write in repair mode.
Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR_QUEUE, TCP_NO_QUEUE);
// Finally, check if socket is still idle. TODO : this check needs to move to
// after starting polling to prevent a race.
- if (!isSocketIdle(fd)) {
+ if (!isReceiveQueueEmpty(fd)) {
+ Log.e(TAG, "Fatal: receive queue of this socket is not empty");
throw new InvalidSocketException(ERROR_INVALID_SOCKET);
}
+ if (!isSendQueueEmpty(fd)) {
+ Log.e(TAG, "Socket is not idle");
+ throw new InvalidSocketException(ERROR_SOCKET_NOT_IDLE);
+ }
// Query tcp window size.
trw = NetworkUtils.getTcpRepairWindow(fd);
+ tcpDetails.rcvWnd = trw.rcvWnd;
+ tcpDetails.rcvWndScale = trw.rcvWndScale;
} catch (ErrnoException e) {
Log.e(TAG, "Exception reading TCP state from socket", e);
if (e.errno == ENOPROTOOPT) {
@@ -194,10 +208,9 @@
// Keepalive sequence number is last sequence number - 1. If it couldn't be retrieved,
// then it must be set to -1, so decrement in all cases.
- seq = seq - 1;
+ tcpDetails.seq = tcpDetails.seq - 1;
- return new TcpSocketInfo(srcAddress, srcPort, dstAddress, dstPort, seq, ack, trw.rcvWnd,
- trw.rcvWndScale);
+ return tcpDetails;
}
/**
@@ -205,10 +218,13 @@
*
* @param fd the fd of socket to switch back to normal.
*/
- // TODO : make this private.
- public static void switchOutOfRepairMode(@NonNull final FileDescriptor fd)
- throws ErrnoException {
- Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
+ private static void switchOutOfRepairMode(@NonNull final FileDescriptor fd) {
+ try {
+ Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Cannot switch socket out of repair mode", e);
+ // Well, there is not much to do here to recover
+ }
}
/**
@@ -262,17 +278,12 @@
mListeners.remove(slot);
}
mFdHandlerQueue.removeOnFileDescriptorEventListener(fd);
- try {
- if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
- switchOutOfRepairMode(fd);
- } catch (ErrnoException e) {
- Log.e(TAG, "Cannot switch socket out of repair mode", e);
- // Well, there is not much to do here to recover
- }
+ if (DBG) Log.d(TAG, "Moving socket out of repair mode for stop : " + fd);
+ switchOutOfRepairMode(fd);
}
- private static InetAddress getAddress(InetSocketAddress inetAddr) {
- return inetAddr.getAddress();
+ private static byte [] getAddress(InetSocketAddress inetAddr) {
+ return inetAddr.getAddress().getAddress();
}
private static int getPort(InetSocketAddress inetAddr) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b79ead0..e2ea42e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -34,6 +34,7 @@
import android.hardware.display.BrightnessConfiguration;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
@@ -51,6 +52,8 @@
import android.view.Display;
import com.android.internal.app.IBatteryStats;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.LocalServices;
import com.android.server.am.BatteryStatsService;
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
@@ -731,6 +734,7 @@
private void updatePowerState() {
// Update the power state request.
final boolean mustNotify;
+ final int previousPolicy;
boolean mustInitialize = false;
synchronized (mLock) {
@@ -745,12 +749,18 @@
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mustInitialize = true;
+ // Assume we're on and bright until told otherwise, since that's the state we turn
+ // on in.
+ previousPolicy = DisplayPowerRequest.POLICY_BRIGHT;
} else if (mPendingRequestChangedLocked) {
+ previousPolicy = mPowerRequest.policy;
mPowerRequest.copyFrom(mPendingRequestLocked);
mWaitingForNegativeProximity |= mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mDisplayReadyLocked = false;
+ } else {
+ previousPolicy = mPowerRequest.policy;
}
mustNotify = !mDisplayReadyLocked;
@@ -1103,6 +1113,10 @@
// Record if dozing for future comparison.
mDozing = state != Display.STATE_ON;
+
+ if (previousPolicy != mPowerRequest.policy) {
+ logDisplayPolicyChanged(mPowerRequest.policy);
+ }
}
@Override
@@ -1523,6 +1537,13 @@
mHandler.post(mOnStateChangedRunnable);
}
+ private void logDisplayPolicyChanged(int newPolicy) {
+ LogMaker log = new LogMaker(MetricsEvent.DISPLAY_POLICY);
+ log.setType(MetricsEvent.TYPE_UPDATE);
+ log.setSubtype(newPolicy);
+ MetricsLogger.action(log);
+ }
+
private void handleSettingsChange(boolean userSwitch) {
mPendingScreenBrightnessSetting = getScreenBrightnessSetting();
if (userSwitch) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 2311776..ed420b7 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -402,6 +402,10 @@
cr.registerContentObserver(Secure.getUriFor(Secure.DISPLAY_WHITE_BALANCE_ENABLED),
false /* notifyForDescendants */, mContentObserver, mCurrentUser);
+ // Apply the accessibility settings first, since they override most other settings.
+ onAccessibilityInversionChanged();
+ onAccessibilityDaltonizerChanged();
+
// Set the color mode, if valid, and immediately apply the updated tint matrix based on the
// existing activated state. This ensures consistency of tint across the color mode change.
onDisplayColorModeChanged(getColorModeInternal());
@@ -1413,7 +1417,7 @@
mCurrentColorTemperature = cct;
// Adapt the display's nominal white point to match the requested CCT value
- mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct);
+ mCurrentColorTemperatureXYZ = ColorSpace.cctToXyz(cct);
mChromaticAdaptationMatrix =
ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD,
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 3c27bf2..430203d 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -332,21 +332,31 @@
* with the test results.
*
* @throws SecurityException if caller is not allowed to manage this service's settings.
+ *
+ * @return whether the enabled state changed.
*/
- public final void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ public final boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
enforceCallingPermissionForManagement();
synchronized (mLock) {
+ final boolean changed = mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
+ if (!changed) {
+ if (verbose) {
+ Slog.v(mTag, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
+ }
+ return false;
+ }
+
final S oldService = peekServiceForUserLocked(userId);
if (oldService != null) {
oldService.removeSelfFromCacheLocked();
}
- mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
// Must update the service on cache so its initialization code is triggered
updateCachedServiceLocked(userId);
}
+ return true;
}
/**
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index cd9ebcd..ac07e9d 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -327,6 +327,10 @@
@GuardedBy("mLock")
protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
pw.print(prefix); pw.print("User: "); pw.println(mUserId);
+ if (mServiceInfo != null) {
+ pw.print(prefix); pw.print("Service Label: "); pw.println(getServiceLabelLocked());
+ pw.print(prefix); pw.print("Target SDK: "); pw.println(getTargedSdkLocked());
+ }
if (mMaster.mServiceNameResolver != null) {
pw.print(prefix); pw.print("Name resolver: ");
mMaster.mServiceNameResolver.dumpShort(pw, mUserId); pw.println();
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index 1b23794..d204813 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -174,23 +174,35 @@
}
@Override
- public void setDefaultServiceEnabled(int userId, boolean enabled) {
+ public boolean setDefaultServiceEnabled(int userId, boolean enabled) {
synchronized (mLock) {
+ final boolean currentlyEnabled = isDefaultServiceEnabledLocked(userId);
+ if (currentlyEnabled == enabled) {
+ Slog.i(TAG, "setDefaultServiceEnabled(" + userId + "): already " + enabled);
+ return false;
+ }
if (enabled) {
+ Slog.i(TAG, "disabling default service for user " + userId);
mDefaultServicesDisabled.removeAt(userId);
} else {
+ Slog.i(TAG, "enabling default service for user " + userId);
mDefaultServicesDisabled.put(userId, true);
}
}
+ return true;
}
@Override
public boolean isDefaultServiceEnabled(int userId) {
synchronized (mLock) {
- return !mDefaultServicesDisabled.get(userId);
+ return isDefaultServiceEnabledLocked(userId);
}
}
+ private boolean isDefaultServiceEnabledLocked(int userId) {
+ return !mDefaultServicesDisabled.get(userId);
+ }
+
@Override
public String toString() {
return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]";
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index 5b60413..8c348ebb 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -115,11 +115,13 @@
*
* @param userId user handle
* @param enabled whether the default service should be used when the temporary service is not
- * set
+ * set. If the service enabled state is already that value, the command is ignored and this
+ * method return {@code false}.
*
+ * @return whether the enabled state changed.
* @throws UnsupportedOperationException if not implemented.
*/
- default void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+ default boolean setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
throw new UnsupportedOperationException("changing default service not supported");
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 150303a..647e952 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -231,7 +231,8 @@
Context.BIND_AUTO_CREATE
| Context.BIND_TREAT_LIKE_ACTIVITY
| Context.BIND_FOREGROUND_SERVICE
- | Context.BIND_SHOWING_UI;
+ | Context.BIND_SHOWING_UI
+ | Context.BIND_SCHEDULE_LIKE_TOP_APP;
@Retention(SOURCE)
@IntDef({HardKeyboardBehavior.WIRELESS_AFFORDANCE, HardKeyboardBehavior.WIRED_AFFORDANCE})
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index cefe583..d5883bb 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -19,6 +19,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.app.ActivityManager;
@@ -2494,24 +2495,36 @@
}
}
- // The expensive check last: validate that the defined package+service is
+ // The expensive check: validate that the defined package+service is
// still present & viable.
- final boolean componentPresent;
+ return isComponentUsable(job);
+ }
+
+ private boolean isComponentUsable(@NonNull JobStatus job) {
+ final ServiceInfo service;
try {
- componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
+ // TODO: cache result until we're notified that something in the package changed.
+ service = AppGlobals.getPackageManager().getServiceInfo(
job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- job.getUserId()) != null);
+ job.getUserId());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
- if (DEBUG) {
- Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
- + " componentPresent=" + componentPresent);
+ if (service == null) {
+ if (DEBUG) {
+ Slog.v(TAG, "isComponentUsable: " + job.toShortString()
+ + " component not present");
+ }
+ return false;
}
// Everything else checked out so far, so this is the final yes/no check
- return componentPresent;
+ final boolean appIsBad = mActivityManagerInternal.isAppBad(service.applicationInfo);
+ if (DEBUG && appIsBad) {
+ Slog.i(TAG, "App is bad for " + job.toShortString() + " so not runnable");
+ }
+ return !appIsBad;
}
private void evaluateControllerStatesLocked(final JobStatus job) {
@@ -2543,30 +2556,18 @@
return false;
}
+ if (isJobThermalConstrainedLocked(job)) {
+ return false;
+ }
+
// Job pending/active doesn't affect the readiness of a job.
- // Skipping the hearbeat check as this will only come into play when using the rolling
+ // Skipping the heartbeat check as this will only come into play when using the rolling
// window quota management system.
- // The expensive check last: validate that the defined package+service is
+ // The expensive check: validate that the defined package+service is
// still present & viable.
- final boolean componentPresent;
- try {
- // TODO: cache result until we're notified that something in the package changed.
- componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
- job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- job.getUserId()) != null);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
-
- if (DEBUG) {
- Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString()
- + " componentPresent=" + componentPresent);
- }
-
- // Everything else checked out so far, so this is the final yes/no check
- return componentPresent;
+ return isComponentUsable(job);
}
/**
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index aca02bf..c820841 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -30,6 +30,9 @@
import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.TrafficStats;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.UserHandle;
import android.text.format.DateUtils;
import android.util.ArraySet;
@@ -85,8 +88,14 @@
@GuardedBy("mLock")
private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
+ private static final int MSG_DATA_SAVER_TOGGLED = 0;
+ private static final int MSG_UID_RULES_CHANGES = 1;
+
+ private final Handler mHandler;
+
public ConnectivityController(JobSchedulerService service) {
super(service);
+ mHandler = new CcHandler(mContext.getMainLooper());
mConnManager = mContext.getSystemService(ConnectivityManager.class);
mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
@@ -545,11 +554,39 @@
private final INetworkPolicyListener mNetPolicyListener = new NetworkPolicyManager.Listener() {
@Override
+ public void onRestrictBackgroundChanged(boolean restrictBackground) {
+ if (DEBUG) {
+ Slog.v(TAG, "onRestrictBackgroundChanged: " + restrictBackground);
+ }
+ mHandler.obtainMessage(MSG_DATA_SAVER_TOGGLED).sendToTarget();
+ }
+
+ @Override
public void onUidRulesChanged(int uid, int uidRules) {
if (DEBUG) {
Slog.v(TAG, "onUidRulesChanged: " + uid);
}
- updateTrackedJobs(uid, null);
+ mHandler.obtainMessage(MSG_UID_RULES_CHANGES, uid, 0).sendToTarget();
+ }
+ };
+
+ private class CcHandler extends Handler {
+ CcHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ switch (msg.what) {
+ case MSG_DATA_SAVER_TOGGLED:
+ updateTrackedJobs(-1, null);
+ break;
+ case MSG_UID_RULES_CHANGES:
+ updateTrackedJobs(msg.arg1, null);
+ break;
+ }
+ }
}
};
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c173d66..8249999 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -166,9 +166,15 @@
private static final int GPS_CAPABILITY_MSA = 0x0000004;
private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
- private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
+
+ // The following three capability flags are removed in IGnssCallback.hal@2.0 and their values
+ // are marked reserved and not reused in 2.0 to avoid confusion with prior versions.
+ public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
- private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+ public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
+
+ private static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
+ private static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
// The AGPS SUPL mode
private static final int AGPS_SUPL_MODE_MSA = 0x02;
@@ -333,7 +339,7 @@
private boolean mStarted;
// capabilities of the GPS engine
- private int mEngineCapabilities;
+ private volatile int mEngineCapabilities;
// true if XTRA is supported
private boolean mSupportsXtra;
@@ -372,6 +378,7 @@
private final LocationExtras mLocationExtras = new LocationExtras();
private final GnssStatusListenerHelper mGnssStatusListenerHelper;
private final GnssMeasurementsProvider mGnssMeasurementsProvider;
+ private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
@@ -437,6 +444,10 @@
return mGnssMeasurementsProvider;
}
+ public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() {
+ return mGnssMeasurementCorrectionsProvider;
+ }
+
public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
return mGnssNavigationMessageProvider;
}
@@ -627,6 +638,8 @@
}
};
+ mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
+
mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
@Override
protected boolean isGpsEnabled() {
@@ -1258,6 +1271,10 @@
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
}
+ public int getGnssCapabilities() {
+ return mEngineCapabilities;
+ }
+
private boolean hasCapability(int capability) {
return ((mEngineCapabilities & capability) != 0);
}
@@ -1467,22 +1484,27 @@
}
@NativeEntryPoint
- private void setEngineCapabilities(final int capabilities) {
+ private void setEngineCapabilities(final int capabilities, boolean hasSubHalCapabilityFlags) {
// send to handler thread for fast native return, and in-order handling
- mHandler.post(
- () -> {
- mEngineCapabilities = capabilities;
+ mHandler.post(() -> {
+ mEngineCapabilities = capabilities;
- if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
- mNtpTimeHelper.enablePeriodicTimeInjection();
- requestUtcTime();
- }
+ if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
+ mNtpTimeHelper.enablePeriodicTimeInjection();
+ requestUtcTime();
+ }
- mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities);
- mGnssNavigationMessageProvider.onCapabilitiesUpdated(
- hasCapability(GPS_CAPABILITY_NAV_MESSAGES));
- restartRequests();
- });
+ mGnssMeasurementsProvider.onCapabilitiesUpdated(capabilities, hasSubHalCapabilityFlags);
+ mGnssNavigationMessageProvider.onCapabilitiesUpdated(capabilities,
+ hasSubHalCapabilityFlags);
+ restartRequests();
+ });
+ }
+
+ @NativeEntryPoint
+ private void setMeasurementCorrectionsCapabilities(final int capabilities) {
+ mHandler.post(() -> mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(
+ capabilities));
}
private void restartRequests() {
@@ -2122,7 +2144,23 @@
if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
+ if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
+ if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
s.append(")\n");
+ if (mGnssGeofenceProvider.isHardwareGeofenceSupported()) {
+ s.append(" hasSubHal=GEOFENCING\n");
+ }
+ if (mGnssMeasurementsProvider.isAvailableInPlatform()) {
+ s.append(" hasSubHal=MEASUREMENTS\n");
+ }
+ if (mGnssNavigationMessageProvider.isAvailableInPlatform()) {
+ s.append(" hasSubHal=NAV_MESSAGES\n");
+ }
+ if (mGnssMeasurementCorrectionsProvider.isAvailableInPlatform()) {
+ s.append(" hasSubHal=MEASUREMENT_CORRECTIONS [");
+ s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities());
+ s.append("]\n");
+ }
s.append(mGnssMetrics.dumpGnssMetricsAsText());
s.append(" native internal state: ").append(native_get_internal_state());
s.append("\n");
diff --git a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
new file mode 100644
index 0000000..2162787
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java
@@ -0,0 +1,149 @@
+/*
+ * 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.location;
+
+import android.location.GnssMeasurementCorrections;
+import android.os.Handler;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Manages GNSS measurement corrections.
+ *
+ * <p>Implements the framework side of the GNSS HAL interfaces {@code IMeasurementCorrections.hal}
+ * and {@code IMeasurementCorrectionsCallback.hal).
+ *
+ * @hide
+ */
+public class GnssMeasurementCorrectionsProvider {
+ private static final String TAG = "GnssMeasurementCorrectionsProvider";
+
+ // These must match with the Capabilities enum in IMeasurementCorrectionsCallback.hal.
+ private static final int CAPABILITY_LOS_SATS = 0x0000001;
+ private static final int CAPABILITY_EXCESS_PATH_LENGTH = 0x0000002;
+ private static final int CAPABILITY_REFLECTING_PLANE = 0x0000004;
+
+ private static final int INVALID_CAPABILITIES = 1 << 31;
+
+ private final Handler mHandler;
+ private final GnssMeasurementCorrectionsProviderNative mNative;
+ private volatile int mCapabilities = INVALID_CAPABILITIES;
+
+ GnssMeasurementCorrectionsProvider(Handler handler) {
+ this(handler, new GnssMeasurementCorrectionsProviderNative());
+ }
+
+ @VisibleForTesting
+ GnssMeasurementCorrectionsProvider(Handler handler,
+ GnssMeasurementCorrectionsProviderNative aNative) {
+ mHandler = handler;
+ mNative = aNative;
+ }
+
+ /**
+ * Returns {@code true} if the GNSS HAL implementation supports measurement corrections.
+ */
+ public boolean isAvailableInPlatform() {
+ return mNative.isMeasurementCorrectionsSupported();
+ }
+
+ /**
+ * Injects GNSS measurement corrections into the GNSS chipset.
+ *
+ * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
+ * measurement corrections to be injected into the GNSS chipset.
+ */
+ public void injectGnssMeasurementCorrections(
+ GnssMeasurementCorrections measurementCorrections) {
+ if (!isCapabilitiesReceived()) {
+ Log.w(TAG, "Failed to inject GNSS measurement corrections. Capabilities "
+ + "not received yet.");
+ return;
+ }
+ mHandler.post(() -> {
+ if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
+ Log.e(TAG, "Failure in injecting GNSS corrections.");
+ }
+ });
+ }
+
+ /** Handle measurement corrections capabilities update from the GNSS HAL implementation. */
+ void onCapabilitiesUpdated(int capabilities) {
+ if (hasCapability(capabilities, CAPABILITY_LOS_SATS) || hasCapability(capabilities,
+ CAPABILITY_EXCESS_PATH_LENGTH)) {
+ mCapabilities = capabilities;
+ } else {
+ Log.e(TAG, "Failed to set capabilities. Received capabilities 0x"
+ + Integer.toHexString(capabilities) + " does not contain the mandatory "
+ + "LOS_SATS or the EXCESS_PATH_LENGTH capability.");
+ }
+ }
+
+ /**
+ * Returns the measurement corrections specific capabilities of the GNSS HAL implementation.
+ */
+ public int getCapabilities() {
+ return mCapabilities;
+ }
+
+ /**
+ * Returns the string representation of the GNSS measurement capabilities.
+ */
+ String toStringCapabilities() {
+ final int capabilities = getCapabilities();
+ StringBuilder s = new StringBuilder();
+ s.append("mCapabilities=0x").append(Integer.toHexString(capabilities));
+ s.append(" ( ");
+ if (hasCapability(capabilities, CAPABILITY_LOS_SATS)) {
+ s.append("LOS_SATS ");
+ }
+ if (hasCapability(capabilities, CAPABILITY_EXCESS_PATH_LENGTH)) {
+ s.append("EXCESS_PATH_LENGTH ");
+ }
+ if (hasCapability(capabilities, CAPABILITY_REFLECTING_PLANE)) {
+ s.append("REFLECTING_PLANE ");
+ }
+ s.append(")");
+ return s.toString();
+ }
+
+ private boolean isCapabilitiesReceived() {
+ return mCapabilities != INVALID_CAPABILITIES;
+ }
+
+ private static boolean hasCapability(int halCapabilities, int capability) {
+ return (halCapabilities & capability) != 0;
+ }
+
+ @VisibleForTesting
+ static class GnssMeasurementCorrectionsProviderNative {
+ public boolean isMeasurementCorrectionsSupported() {
+ return native_is_measurement_corrections_supported();
+ }
+
+ public boolean injectGnssMeasurementCorrections(
+ GnssMeasurementCorrections measurementCorrections) {
+ return native_inject_gnss_measurement_corrections(measurementCorrections);
+ }
+ }
+
+ private static native boolean native_is_measurement_corrections_supported();
+
+ private static native boolean native_inject_gnss_measurement_corrections(
+ GnssMeasurementCorrections measurementCorrections);
+}
diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
index 1fc7192..844735a 100644
--- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/GnssMeasurementsProvider.java
@@ -11,13 +11,12 @@
* 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
+ * limitations under the License.
*/
package com.android.server.location;
import android.content.Context;
-import android.location.GnssMeasurementCorrections;
import android.location.GnssMeasurementsEvent;
import android.location.IGnssMeasurementsListener;
import android.os.Handler;
@@ -42,7 +41,6 @@
private boolean mIsCollectionStarted;
private boolean mEnableFullTracking;
- private int mGnssEngineCapabilities;
protected GnssMeasurementsProvider(Context context, Handler handler) {
this(context, handler, new GnssMeasurementProviderNative());
@@ -87,21 +85,6 @@
}
}
- /**
- * Injects GNSS measurement corrections into the GNSS chipset.
- *
- * @param measurementCorrections a {@link GnssMeasurementCorrections} object with the GNSS
- * measurement corrections to be injected into the GNSS chipset.
- */
- public void injectGnssMeasurementCorrections(
- GnssMeasurementCorrections measurementCorrections) {
- mHandler.post(() -> {
- if (!mNative.injectGnssMeasurementCorrections(measurementCorrections)) {
- Log.e(TAG, "Failure in injecting GNSS corrections.");
- }
- });
- }
-
@Override
protected void unregisterFromService() {
boolean stopped = mNative.stopMeasurementCollection();
@@ -121,20 +104,20 @@
});
}
- /** Updates the framework about the capabilities of the GNSS chipset */
- public void onCapabilitiesUpdated(int capabilities) {
- mGnssEngineCapabilities = capabilities;
- boolean isGnssMeasurementsSupported =
- (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0;
+ /** Handle GNSS capabilities update from the GNSS HAL implementation. */
+ public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
+ final boolean isGnssMeasurementsSupported = hasSubHalCapabilityFlags
+ ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_MEASUREMENTS) != 0
+ : mNative.isMeasurementSupported();
setSupported(isGnssMeasurementsSupported);
updateResult();
}
- /** Obtains the GNSS engine capabilities. */
- public int getGnssCapabilities() {
- return mGnssEngineCapabilities;
- }
-
public void onGpsEnabledChanged() {
tryUpdateRegistrationWithService();
updateResult();
@@ -195,11 +178,6 @@
public boolean stopMeasurementCollection() {
return native_stop_measurement_collection();
}
-
- public boolean injectGnssMeasurementCorrections(
- GnssMeasurementCorrections measurementCorrections) {
- return native_inject_gnss_measurement_corrections(measurementCorrections);
- }
}
private static native boolean native_is_measurement_supported();
@@ -207,7 +185,4 @@
private static native boolean native_start_measurement_collection(boolean enableFullTracking);
private static native boolean native_stop_measurement_collection();
-
- private static native boolean native_inject_gnss_measurement_corrections(
- GnssMeasurementCorrections measurementCorrections);
}
diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
index 80a3f9b..7e8b599 100644
--- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
+++ b/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
@@ -11,7 +11,7 @@
* 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
+ * limitations under the License.
*/
package com.android.server.location;
@@ -51,7 +51,6 @@
mNative = aNative;
}
- // TODO(b/37460011): Use this with death recovery logic.
void resumeIfStarted() {
if (DEBUG) {
Log.d(TAG, "resumeIfStarted");
@@ -92,7 +91,16 @@
);
}
- public void onCapabilitiesUpdated(boolean isGnssNavigationMessageSupported) {
+ /** Handle GNSS capabilities update from the GNSS HAL implementation */
+ public void onCapabilitiesUpdated(int capabilities, boolean hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
+ final boolean isGnssNavigationMessageSupported = hasSubHalCapabilityFlags
+ ? (capabilities & GnssLocationProvider.GPS_CAPABILITY_NAV_MESSAGES) != 0
+ : mNative.isNavigationMessageSupported();
setSupported(isGnssNavigationMessageSupported);
updateResult();
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a53ab84..293813a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2699,6 +2699,14 @@
}
}
+ @Override
+ public boolean hasPendingEscrowToken(int userId) {
+ checkPasswordReadPermission(userId);
+ synchronized (mSpManager) {
+ return !mSpManager.getPendingTokensForUser(userId).isEmpty();
+ }
+ }
+
private boolean removeEscrowToken(long handle, int userId) {
synchronized (mSpManager) {
if (handle == getSyntheticPasswordHandleLocked(userId)) {
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 142ad53..1ba0e8c 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -751,7 +751,7 @@
/**
* Create a token based Synthetic password for the given user.
- * @return
+ * @return the handle of the token
*/
public long createTokenBasedSyntheticPassword(byte[] token, int userId,
@Nullable EscrowTokenStateChangeCallback changeCallback) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 152cf7f..7b691b4 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -24,17 +24,18 @@
import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.MediaMetadata;
+import android.media.MediaParceledListSlice;
import android.media.Rating;
import android.media.VolumeProvider;
import android.media.session.ControllerCallbackLink;
-import android.media.session.ControllerLink;
+import android.media.session.ISession;
+import android.media.session.ISessionController;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
import android.media.session.PlaybackState;
import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -44,6 +45,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.util.Log;
@@ -78,9 +80,9 @@
private final String mPackageName;
private final String mTag;
private final Bundle mSessionInfo;
- private final ControllerLink mController;
+ private final ControllerStub mController;
private final MediaSession.Token mSessionToken;
- private final SessionLink mSession;
+ private final SessionStub mSession;
private final SessionCb mSessionCb;
private final MediaSessionService.ServiceImpl mService;
private final Context mContext;
@@ -130,9 +132,9 @@
mPackageName = ownerPackageName;
mTag = tag;
mSessionInfo = sessionInfo;
- mController = new ControllerLink(new ControllerStub());
+ mController = new ControllerStub();
mSessionToken = new MediaSession.Token(mController);
- mSession = new SessionLink(new SessionStub());
+ mSession = new SessionStub();
mSessionCb = new SessionCb(cb);
mService = service;
mContext = mService.getContext();
@@ -143,20 +145,20 @@
}
/**
- * Get the session link for the {@link MediaSession}.
+ * Get the session binder for the {@link MediaSession}.
*
- * @return The session link apps talk to.
+ * @return The session binder apps talk to.
*/
- public SessionLink getSessionBinder() {
+ public ISession getSessionBinder() {
return mSession;
}
/**
- * Get the controller link for the {@link MediaController}.
+ * Get the controller binder for the {@link MediaController}.
*
- * @return The controller link apps talk to.
+ * @return The controller binder apps talk to.
*/
- public ControllerLink getControllerLink() {
+ public ISessionController getControllerBinder() {
return mController;
}
@@ -817,9 +819,9 @@
}
};
- private final class SessionStub extends SessionLink.SessionStub {
+ private final class SessionStub extends ISession.Stub {
@Override
- public void destroySession() {
+ public void destroySession() throws RemoteException {
final long token = Binder.clearCallingIdentity();
try {
mService.destroySession(MediaSessionRecord.this);
@@ -829,18 +831,18 @@
}
@Override
- public void sendEvent(String event, Bundle data) {
+ public void sendEvent(String event, Bundle data) throws RemoteException {
mHandler.post(MessageHandler.MSG_SEND_EVENT, event,
data == null ? null : new Bundle(data));
}
@Override
- public ControllerLink getController() {
+ public ISessionController getController() throws RemoteException {
return mController;
}
@Override
- public void setActive(boolean active) {
+ public void setActive(boolean active) throws RemoteException {
mIsActive = active;
final long token = Binder.clearCallingIdentity();
try {
@@ -852,7 +854,7 @@
}
@Override
- public void setFlags(int flags) {
+ public void setFlags(int flags) throws RemoteException {
if ((flags & MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY) != 0) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
@@ -871,7 +873,7 @@
}
@Override
- public void setMediaButtonReceiver(PendingIntent pi) {
+ public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
mMediaButtonReceiver = pi;
final long token = Binder.clearCallingIdentity();
try {
@@ -882,12 +884,13 @@
}
@Override
- public void setLaunchPendingIntent(PendingIntent pi) {
+ public void setLaunchPendingIntent(PendingIntent pi) throws RemoteException {
mLaunchIntent = pi;
}
@Override
- public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription) {
+ public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)
+ throws RemoteException {
synchronized (mLock) {
MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata)
.build();
@@ -905,7 +908,7 @@
}
@Override
- public void setPlaybackState(PlaybackState state) {
+ public void setPlaybackState(PlaybackState state) throws RemoteException {
int oldState = mPlaybackState == null
? PlaybackState.STATE_NONE : mPlaybackState.getState();
int newState = state == null
@@ -923,21 +926,21 @@
}
@Override
- public void setQueue(List<QueueItem> queue) {
+ public void setQueue(MediaParceledListSlice queue) throws RemoteException {
synchronized (mLock) {
- mQueue = queue;
+ mQueue = queue == null ? null : (List<QueueItem>) queue.getList();
}
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE);
}
@Override
- public void setQueueTitle(CharSequence title) {
+ public void setQueueTitle(CharSequence title) throws RemoteException {
mQueueTitle = title;
mHandler.post(MessageHandler.MSG_UPDATE_QUEUE_TITLE);
}
@Override
- public void setExtras(Bundle extras) {
+ public void setExtras(Bundle extras) throws RemoteException {
synchronized (mLock) {
mExtras = extras == null ? null : new Bundle(extras);
}
@@ -945,18 +948,18 @@
}
@Override
- public void setRatingType(int type) {
+ public void setRatingType(int type) throws RemoteException {
mRatingType = type;
}
@Override
- public void setCurrentVolume(int volume) {
+ public void setCurrentVolume(int volume) throws RemoteException {
mCurrentVolume = volume;
mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
}
@Override
- public void setPlaybackToLocal(AudioAttributes attributes) {
+ public void setPlaybackToLocal(AudioAttributes attributes) throws RemoteException {
boolean typeChanged;
synchronized (mLock) {
typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
@@ -979,7 +982,7 @@
}
@Override
- public void setPlaybackToRemote(int control, int max) {
+ public void setPlaybackToRemote(int control, int max) throws RemoteException {
boolean typeChanged;
synchronized (mLock) {
typeChanged = mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL;
@@ -1248,7 +1251,7 @@
}
}
- class ControllerStub extends ControllerLink.ControllerStub {
+ class ControllerStub extends ISessionController.Stub {
@Override
public void sendCommand(String packageName, ControllerCallbackLink caller,
String command, Bundle args, ResultReceiver cb) {
@@ -1488,9 +1491,9 @@
}
@Override
- public List<QueueItem> getQueue() {
+ public MediaParceledListSlice getQueue() {
synchronized (mLock) {
- return mQueue;
+ return mQueue == null ? null : new MediaParceledListSlice<>(mQueue);
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 94f289f..7c8dc74 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -49,12 +49,12 @@
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
import android.media.session.IOnVolumeKeyLongPressListener;
+import android.media.session.ISession;
import android.media.session.ISession2TokensListener;
import android.media.session.ISessionManager;
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.SessionCallbackLink;
-import android.media.session.SessionLink;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -1001,7 +1001,7 @@
private boolean mVoiceButtonHandled = false;
@Override
- public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag,
+ public ISession createSession(String packageName, SessionCallbackLink cb, String tag,
Bundle sessionInfo, int userId) throws RemoteException {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 9ba50ee..a5e7d8e 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -144,7 +144,7 @@
*/
public MediaSessionRecord getMediaSessionRecord(MediaSession.Token sessionToken) {
for (MediaSessionRecord record : mSessions) {
- if (Objects.equals(record.getControllerLink(), sessionToken.getControllerLink())) {
+ if (Objects.equals(record.getControllerBinder(), sessionToken.getBinder())) {
return record;
}
}
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 8adea0e..4bc9373 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -1,4 +1,6 @@
-lajos@google.com
elaurent@google.com
-sungsoo@google.com
+hdmoon@google.com
+insun@google.com
jaewan@google.com
+lajos@google.com
+sungsoo@google.com
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 270fbc6..3872523 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -17,9 +17,14 @@
package com.android.server.media.projection;
import android.Manifest;
+import android.app.ActivityManagerInternal;
import android.app.AppOpsManager;
+import android.app.IProcessObserver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ServiceInfo;
import android.hardware.display.DisplayManager;
import android.media.MediaRouter;
import android.media.projection.IMediaProjection;
@@ -29,6 +34,8 @@
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Binder;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -38,6 +45,7 @@
import android.util.Slog;
import com.android.internal.util.DumpUtils;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
@@ -63,6 +71,8 @@
private final Context mContext;
private final AppOpsManager mAppOps;
+ private final ActivityManagerInternal mActivityManagerInternal;
+ private final PackageManager mPackageManager;
private final MediaRouter mMediaRouter;
private final MediaRouterCallback mMediaRouterCallback;
@@ -77,6 +87,8 @@
mDeathEaters = new ArrayMap<IBinder, IBinder.DeathRecipient>();
mCallbackDelegate = new CallbackDelegate();
mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+ mPackageManager = mContext.getPackageManager();
mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
mMediaRouterCallback = new MediaRouterCallback();
Watchdog.getInstance().addMonitor(this);
@@ -88,6 +100,21 @@
false /*allowIsolated*/);
mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback,
MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY);
+ mActivityManagerInternal.registerProcessObserver(new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean fg) {
+ }
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ MediaProjectionManagerService.this.handleForegroundServicesChanged(pid, uid,
+ serviceTypes);
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ }
+ });
}
@Override
@@ -105,6 +132,29 @@
synchronized (mLock) { /* check for deadlock */ }
}
+ /**
+ * Called when the set of active foreground service types for a given {@code uid / pid} changes.
+ * We will stop the active projection grant if its owner targets {@code Q} or higher and has no
+ * started foreground services of type {@code FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION}.
+ */
+ private void handleForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ synchronized (mLock) {
+ if (mProjectionGrant == null || mProjectionGrant.uid != uid) {
+ return;
+ }
+
+ if (mProjectionGrant.targetSdkVersion < VERSION_CODES.Q) {
+ return;
+ }
+
+ if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) {
+ return;
+ }
+
+ mProjectionGrant.stop();
+ }
+ }
+
private void startProjectionLocked(final MediaProjection projection) {
if (mProjectionGrant != null) {
mProjectionGrant.stop();
@@ -229,10 +279,19 @@
if (packageName == null || packageName.isEmpty()) {
throw new IllegalArgumentException("package name must not be empty");
}
+
long callingToken = Binder.clearCallingIdentity();
+
MediaProjection projection;
try {
- projection = new MediaProjection(type, uid, packageName);
+ ApplicationInfo ai;
+ try {
+ ai = mPackageManager.getApplicationInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("No package matching :" + packageName);
+ }
+
+ projection = new MediaProjection(type, uid, packageName, ai.targetSdkVersion);
if (isPermanentGrant) {
mAppOps.setMode(AppOpsManager.OP_PROJECT_MEDIA,
projection.uid, projection.packageName, AppOpsManager.MODE_ALLOWED);
@@ -334,17 +393,19 @@
public final int uid;
public final String packageName;
public final UserHandle userHandle;
+ public final int targetSdkVersion;
private IMediaProjectionCallback mCallback;
private IBinder mToken;
private IBinder.DeathRecipient mDeathEater;
private int mType;
- public MediaProjection(int type, int uid, String packageName) {
+ MediaProjection(int type, int uid, String packageName, int targetSdkVersion) {
mType = type;
this.uid = uid;
this.packageName = packageName;
userHandle = new UserHandle(UserHandle.getUserId(uid));
+ this.targetSdkVersion = targetSdkVersion;
}
@Override // Binder call
@@ -400,6 +461,14 @@
+ " attempted to start already started MediaProjection");
return;
}
+
+ if (targetSdkVersion >= Build.VERSION_CODES.Q
+ && !mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ throw new SecurityException("Media projections require a foreground service"
+ + " of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION");
+ }
+
mCallback = callback;
registerCallback(mCallback);
try {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 0c0c23a..0488d3a 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -347,6 +347,9 @@
}
}
}
+
+ writeExtraXmlTags(out);
+
out.endTag(null, getConfig().xmlTag);
}
@@ -355,6 +358,16 @@
*/
protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
+ /**
+ * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
+ */
+ protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
+
+ /**
+ * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
+ */
+ protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
+
protected void migrateToXml() {
loadAllowedComponentsFromSettings();
}
@@ -391,6 +404,8 @@
}
mUseXml = true;
}
+ } else {
+ readExtraTag(tag, parser);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 88e697c..ca3c826 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -294,6 +294,12 @@
static final boolean ENABLE_BLOCKED_TOASTS = true;
+ static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
+ Adjustment.KEY_IMPORTANCE,
+ Adjustment.KEY_CONTEXTUAL_ACTIONS,
+ Adjustment.KEY_TEXT_REPLIES,
+ Adjustment.KEY_USER_SENTIMENT};
+
// When #matchesCallFilter is called from the ringer, wait at most
// 3s to resolve the contacts. This timeout is required since
// ContactsProvider might take a long time to start up.
@@ -2504,15 +2510,23 @@
}
@Override
- public boolean canNotifyAsPackage(String callingPkg, String targetPkg) {
+ public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) {
checkCallerIsSameApp(callingPkg);
final int callingUid = Binder.getCallingUid();
UserHandle user = UserHandle.getUserHandleForUid(callingUid);
+ if (user.getIdentifier() != userId) {
+ getContext().enforceCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ "canNotifyAsPackage for user " + userId);
+ }
+ if (callingPkg.equals(targetPkg)) {
+ return true;
+ }
try {
ApplicationInfo info =
mPackageManager.getApplicationInfo(targetPkg,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
- user.getIdentifier());
+ userId);
if (info != null) {
return mPreferencesHelper.isDelegateAllowed(
targetPkg, info.uid, callingPkg, callingUid);
@@ -2577,10 +2591,21 @@
}
@Override
- public NotificationChannel getNotificationChannel(String pkg, String channelId) {
- checkCallerIsSystemOrSameApp(pkg);
- return mPreferencesHelper.getNotificationChannel(
- pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
+ public NotificationChannel getNotificationChannel(String callingPkg, int userId,
+ String targetPkg, String channelId) {
+ if (canNotifyAsPackage(callingPkg, targetPkg, userId)
+ || isCallingUidSystem()) {
+ int targetUid = -1;
+ try {
+ targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ return mPreferencesHelper.getNotificationChannel(
+ targetPkg, targetUid, channelId, false /* includeDeleted */);
+ }
+ throw new SecurityException("Pkg " + callingPkg
+ + " cannot read channels for " + targetPkg + " in " + userId);
}
@Override
@@ -2715,10 +2740,21 @@
}
@Override
- public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
- checkCallerIsSystemOrSameApp(pkg);
- return mPreferencesHelper.getNotificationChannels(
- pkg, Binder.getCallingUid(), false /* includeDeleted */);
+ public ParceledListSlice<NotificationChannel> getNotificationChannels(
+ String callingPkg, String targetPkg, int userId) {
+ if (canNotifyAsPackage(callingPkg, targetPkg, userId)
+ || isCallingUidSystem()) {
+ int targetUid = -1;
+ try {
+ targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
+ } catch (NameNotFoundException e) {
+ /* ignore */
+ }
+ return mPreferencesHelper.getNotificationChannels(
+ targetPkg, targetUid, false /* includeDeleted */);
+ }
+ throw new SecurityException("Pkg " + callingPkg
+ + " cannot read channels for " + targetPkg + " in " + userId);
}
@Override
@@ -2785,6 +2821,33 @@
handleSavePolicyFile();
}
+ @Override
+ public List<String> getAllowedAssistantCapabilities(String pkg) {
+ checkCallerIsSystemOrSameApp(pkg);
+
+ if (!isCallerSystemOrPhone()
+ && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
+ throw new SecurityException("Not currently an assistant");
+ }
+
+ return mAssistants.getAllowedAssistantCapabilities();
+ }
+
+ @Override
+ public void allowAssistantCapability(String adjustmentType) {
+ checkCallerIsSystemOrShell();
+ mAssistants.allowAdjustmentType(adjustmentType);
+
+ handleSavePolicyFile();
+ }
+
+ @Override
+ public void disallowAssistantCapability(String adjustmentType) {
+ checkCallerIsSystemOrShell();
+ mAssistants.disallowAdjustmentType(adjustmentType);
+
+ handleSavePolicyFile();
+ }
/**
* System-only API for getting a list of current (i.e. not cleared) notifications.
@@ -7138,15 +7201,26 @@
static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
private static final String ATT_USER_SET = "user_set";
+ // TODO: STOPSHIP (b/127994217) switch to final value when onboarding flow is implemented
+ private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "allowed_adjustments_tmp";
+ private static final String ATT_TYPES = "types";
private final Object mLock = new Object();
@GuardedBy("mLock")
private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
+ private List<String> mAllowedAdjustments = new ArrayList<>();
public NotificationAssistants(Context context, Object lock, UserProfiles up,
IPackageManager pm) {
super(context, lock, up, pm);
+
+ // TODO: STOPSHIP (b/127994217) remove when the onboarding flow is implemented
+ // Add all default allowed adjustment types. Will be overwritten by values in xml,
+ // if they exist
+ for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
+ mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
+ }
}
@Override
@@ -7197,6 +7271,48 @@
return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
}
+ @Override
+ protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
+ synchronized (mLock) {
+ out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
+ out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
+ out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
+ }
+ }
+
+ @Override
+ protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
+ if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
+ final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
+ if (!TextUtils.isEmpty(types)) {
+ synchronized (mLock) {
+ mAllowedAdjustments.clear();
+ mAllowedAdjustments.addAll(Arrays.asList(types.split(",")));
+ }
+ }
+ }
+ }
+
+ protected void allowAdjustmentType(String type) {
+ synchronized (mLock) {
+ mAllowedAdjustments.add(type);
+ }
+ }
+
+ protected void disallowAdjustmentType(String type) {
+ synchronized (mLock) {
+ mAllowedAdjustments.remove(type);
+ }
+ }
+
+ protected List<String> getAllowedAssistantCapabilities() {
+ synchronized (mLock) {
+ List<String> types = new ArrayList<>();
+ types.addAll(mAllowedAdjustments);
+ return types;
+ }
+ }
+
protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index d9ab132..de93120 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -438,6 +438,8 @@
if (getAudioAttributes() != null) {
getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
}
+ proto.write(NotificationRecordProto.PACKAGE, sbn.getPackageName());
+ proto.write(NotificationRecordProto.DELEGATE_PACKAGE, sbn.getOpPkg());
proto.end(token);
}
@@ -458,6 +460,7 @@
pw.println(prefix + this);
prefix = prefix + " ";
pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
+ pw.println(prefix + "opPkg=" + sbn.getOpPkg());
pw.println(prefix + "icon=" + iconStr);
pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
pw.println(prefix + "pri=" + notification.priority);
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 9e0cb0f..fd68a8b 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -82,7 +82,7 @@
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
try {
if (FEATURE_FLAG_IDMAP2) {
- int policies = determineFulfilledPolicies(targetPackage, overlayPackage, userId);
+ int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
boolean enforce = enforceOverlayable(overlayPackage);
if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
return true;
@@ -184,28 +184,25 @@
return true;
}
- if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) {
+ if (ai.isVendor()) {
// If the overlay is on a pre-Q vendor partition, do not enforce overlayable
// restrictions on this overlay because the pre-Q platform has no understanding of
// overlayable.
- return false;
+ return VENDOR_IS_Q_OR_LATER;
}
- // Do not enforce overlayable restrictions on pre-Q overlays signed with the
- // platform signature.
- return !ai.isSignedWithPlatformKey();
+ // Do not enforce overlayable restrictions on pre-Q overlays that are signed with the
+ // platform signature or that are preinstalled.
+ return !(ai.isSystemApp() || ai.isSignedWithPlatformKey());
}
/**
- * Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills.
- * @throws SecurityException if the overlay is not allowed to overlay any resource
+ * Retrieves a bitmask for idmap2 that represents the policies the overlay fulfills.
*/
- private int determineFulfilledPolicies(@NonNull final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, int userId) throws SecurityException {
+ private int calculateFulfilledPolicies(@NonNull final PackageInfo targetPackage,
+ @NonNull final PackageInfo overlayPackage, int userId) {
final ApplicationInfo ai = overlayPackage.applicationInfo;
- final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q;
-
- int fulfilledPolicies = 0;
+ int fulfilledPolicies = IIdmap2.POLICY_PUBLIC;
// Overlay matches target signature
if (mPackageManager.signaturesMatching(targetPackage.packageName,
@@ -215,32 +212,25 @@
// Vendor partition (/vendor)
if (ai.isVendor()) {
- if (overlayIsQOrLater) {
- fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION;
- } else if (VENDOR_IS_Q_OR_LATER) {
- throw new SecurityException("Overlay must target Q sdk or higher");
- }
+ return fulfilledPolicies | IIdmap2.POLICY_VENDOR_PARTITION;
}
// Product partition (/product)
if (ai.isProduct()) {
- if (overlayIsQOrLater) {
- fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION;
- } else {
- throw new SecurityException("Overlay must target Q sdk or higher");
- }
+ return fulfilledPolicies | IIdmap2.POLICY_PRODUCT_PARTITION;
}
- // System partition (/system)
+ // Check partitions for which there exists no policy so overlays on these partitions will
+ // not fulfill the system policy.
+ if (ai.isOem() || ai.isProductServices()) {
+ return fulfilledPolicies;
+ }
+
+ // Check this last since every partition except for data is scanned as system in the PMS.
if (ai.isSystemApp()) {
- if (overlayIsQOrLater) {
- fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION;
- } else {
- throw new SecurityException("Overlay must target Q sdk or higher");
- }
+ return fulfilledPolicies | IIdmap2.POLICY_SYSTEM_PARTITION;
}
- // All overlays can overlay resources with the public policy
- return fulfilledPolicies | IIdmap2.POLICY_PUBLIC;
+ return fulfilledPolicies;
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 8905eb9..37dd63a 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -758,7 +758,7 @@
* @throws SecurityException if the permission check fails
*/
private void enforceChangeOverlayPackagesPermission(@NonNull final String message) {
- getContext().enforceCallingPermission(
+ getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, message);
}
@@ -769,7 +769,7 @@
* @throws SecurityException if the permission check fails
*/
private void enforceDumpPermission(@NonNull final String message) {
- getContext().enforceCallingPermission(android.Manifest.permission.DUMP, message);
+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, message);
}
};
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 7f057f0..18cfa4a 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -45,8 +45,6 @@
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
import android.graphics.Rect;
import android.net.Uri;
@@ -62,31 +60,21 @@
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.provider.Settings;
-import android.util.ByteStringUtils;
import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.StatLogger;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.wm.ActivityTaskManagerInternal;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
/**
* Service that manages requests and callbacks for launchers that support
@@ -125,16 +113,6 @@
private static final boolean DEBUG = false;
private static final String TAG = "LauncherAppsService";
- // Stats
- @VisibleForTesting
- interface Stats {
- int INIT_VOUCHED_SIGNATURES = 0;
- int COUNT = INIT_VOUCHED_SIGNATURES + 1;
- }
- private final StatLogger mStatLogger = new StatLogger(new String[] {
- "initVouchedSignatures"
- });
-
private final Context mContext;
private final UserManager mUm;
private final UserManagerInternal mUserManagerInternal;
@@ -145,16 +123,11 @@
private final PackageCallbackList<IOnAppsChangedListener> mListeners
= new PackageCallbackList<IOnAppsChangedListener>();
private final DevicePolicyManager mDpm;
- private final ConcurrentHashMap<UserHandle, Set<String>> mVouchedSignaturesByUser;
- private final Set<String> mVouchProviders;
private final MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
- private final VouchesChangedMonitor mVouchesChangedMonitor = new VouchesChangedMonitor();
private final Handler mCallbackHandler;
- private final Object mVouchedSignaturesLocked = new Object();
-
private PackageInstallerService mPackageInstallerService;
public LauncherAppsImpl(Context context) {
@@ -173,9 +146,6 @@
mShortcutServiceInternal.addListener(mPackageMonitor);
mCallbackHandler = BackgroundThread.getHandler();
mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
- mVouchedSignaturesByUser = new ConcurrentHashMap<>();
- mVouchProviders = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
- mVouchesChangedMonitor.register(mContext, UserHandle.ALL, true, mCallbackHandler);
}
@VisibleForTesting
@@ -468,32 +438,9 @@
if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {
return false;
}
- if (!mVouchedSignaturesByUser.containsKey(user)) {
- initVouchedSignatures(user);
- }
if (isManagedProfileAdmin(user, appInfo.packageName)) {
return false;
}
- if (mVouchProviders.contains(appInfo.packageName)) {
- // If it's a vouching packages then we must show hidden app
- return true;
- }
- // If app's signature is in vouch list, do not show hidden app
- final Set<String> vouches = mVouchedSignaturesByUser.get(user);
- try {
- final PackageInfo pkgInfo = mContext.getPackageManager().getPackageInfo(
- appInfo.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
- final Signature[] signatures = getLatestSignatures(pkgInfo.signingInfo);
- // If any of the signatures appears in vouches, then we don't show hidden app
- for (Signature signature : signatures) {
- final String certDigest = computePackageCertDigest(signature);
- if (vouches.contains(certDigest)) {
- return false;
- }
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Should not happen
- }
return true;
}
@@ -515,100 +462,6 @@
return false;
}
- @VisibleForTesting
- static String computePackageCertDigest(Signature signature) {
- MessageDigest messageDigest;
- try {
- messageDigest = MessageDigest.getInstance("SHA1");
- } catch (NoSuchAlgorithmException e) {
- // Should not happen
- return null;
- }
- messageDigest.update(signature.toByteArray());
- final byte[] digest = messageDigest.digest();
- return ByteStringUtils.toHexString(digest);
- }
-
- @VisibleForTesting
- static Signature[] getLatestSignatures(SigningInfo signingInfo) {
- if (signingInfo.hasMultipleSigners()) {
- return signingInfo.getApkContentsSigners();
- } else {
- final Signature[] signatures = signingInfo.getSigningCertificateHistory();
- return new Signature[]{signatures[0]};
- }
- }
-
- private void updateVouches(String packageName, UserHandle user) {
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- ApplicationInfo appInfo = pmInt.getApplicationInfo(packageName,
- PackageManager.GET_META_DATA, Binder.getCallingUid(), user.getIdentifier());
- if (appInfo == null) {
- Log.w(TAG, "appInfo " + packageName + " is null");
- return;
- }
- updateVouches(appInfo, user);
- }
-
- private void updateVouches(ApplicationInfo appInfo, UserHandle user) {
- if (appInfo == null || appInfo.metaData == null) {
- // No meta-data
- return;
- }
- int tokenResourceId = appInfo.metaData.getInt(LauncherApps.VOUCHED_CERTS_KEY);
- if (tokenResourceId == 0) {
- // No xml file
- return;
- }
- mVouchProviders.add(appInfo.packageName);
- Set<String> vouches = mVouchedSignaturesByUser.get(user);
- try {
- List<String> signatures = Arrays.asList(
- mContext.getPackageManager().getResourcesForApplication(
- appInfo.packageName).getStringArray(tokenResourceId));
- for (String signature : signatures) {
- vouches.add(signature.toUpperCase());
- }
- } catch (PackageManager.NameNotFoundException e) {
- // Should not happen
- }
- }
-
- private void initVouchedSignatures(UserHandle user) {
- synchronized (mVouchedSignaturesLocked) {
- if (mVouchedSignaturesByUser.contains(user)) {
- return;
- }
- final long startTime = mStatLogger.getTime();
-
- Set<String> vouches = Collections.newSetFromMap(
- new ConcurrentHashMap<String, Boolean>());
-
- final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
- try {
- final PackageManagerInternal pmInt =
- LocalServices.getService(PackageManagerInternal.class);
- List<ApplicationInfo> installedPackages = pmInt.getInstalledApplications(
- PackageManager.GET_META_DATA, user.getIdentifier(), callingUid);
- for (ApplicationInfo appInfo : installedPackages) {
- updateVouches(appInfo, user);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- mVouchedSignaturesByUser.putIfAbsent(user, vouches);
- mStatLogger.logDurationStat(Stats.INIT_VOUCHED_SIGNATURES, startTime);
- }
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
- mStatLogger.dump(pw, " ");
- }
-
@Override
public ActivityInfo resolveActivity(
String callingPackage, ComponentName component, UserHandle user)
@@ -1022,18 +875,6 @@
mCallbackHandler.post(r);
}
- private class VouchesChangedMonitor extends PackageMonitor {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- updateVouches(packageName, new UserHandle(getChangingUserId()));
- }
-
- @Override
- public void onPackageModified(String packageName) {
- updateVouches(packageName, new UserHandle(getChangingUserId()));
- }
- }
-
private class MyPackageMonitor extends PackageMonitor implements ShortcutChangeListener {
// TODO Simplify with lambdas.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 181b7a2..ad17549 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -123,6 +123,8 @@
/** Automatically destroy sessions older than this */
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
+ /** Automatically destroy staged sessions that have not changed state in this time */
+ private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
/** Upper bound on number of active sessions for a UID */
private static final long MAX_ACTIVE_SESSIONS = 1024;
/** Upper bound on number of historical sessions for a UID */
@@ -357,11 +359,19 @@
}
final long age = System.currentTimeMillis() - session.createdMillis;
-
+ final long timeSinceUpdate =
+ System.currentTimeMillis() - session.updatedMillis;
final boolean valid;
- if (age >= MAX_AGE_MILLIS) {
- Slog.w(TAG, "Abandoning old session first created at "
- + session.createdMillis);
+ if (session.isStaged()) {
+ if (timeSinceUpdate >= MAX_TIME_SINCE_UPDATE_MILLIS
+ && session.isStagedAndInTerminalState()) {
+ valid = false;
+ } else {
+ valid = true;
+ }
+ } else if (age >= MAX_AGE_MILLIS) {
+ Slog.w(TAG, "Abandoning old session created at "
+ + session.createdMillis);
valid = false;
} else {
valid = true;
@@ -1196,6 +1206,7 @@
}
public void onStagedSessionChanged(PackageInstallerSession session) {
+ session.markUpdated();
writeSessionsAsync();
if (mOkToSendBroadcasts) {
mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 775854b..66b530f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -144,6 +144,7 @@
private static final String ATTR_INSTALLER_PACKAGE_NAME = "installerPackageName";
private static final String ATTR_INSTALLER_UID = "installerUid";
private static final String ATTR_CREATED_MILLIS = "createdMillis";
+ private static final String ATTR_UPDATED_MILLIS = "updatedMillis";
private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir";
private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid";
private static final String ATTR_PREPARED = "prepared";
@@ -199,6 +200,10 @@
private final Object mLock = new Object();
+ /** Timestamp of the last time this session changed state */
+ @GuardedBy("mLock")
+ long updatedMillis;
+
/** Uid of the creator of this session. */
private final int mOriginalInstallerUid;
@@ -422,6 +427,7 @@
mInstallerUid = installerUid;
this.params = params;
this.createdMillis = createdMillis;
+ this.updatedMillis = createdMillis;
this.stageDir = stageDir;
this.stageCid = stageCid;
if (childSessionIds != null) {
@@ -521,6 +527,13 @@
}
}
+ /** Returns true if a staged session has reached a final state and can be forgotten about */
+ public boolean isStagedAndInTerminalState() {
+ synchronized (mLock) {
+ return params.isStaged && (mStagedSessionApplied || mStagedSessionFailed);
+ }
+ }
+
@GuardedBy("mLock")
private void assertPreparedAndNotSealedLocked(String cookie) {
assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
@@ -995,6 +1008,19 @@
mSealed = true;
+ if (params.isStaged) {
+ final PackageInstallerSession activeSession = mStagingManager.getActiveSession();
+ final boolean anotherSessionAlreadyInProgress =
+ activeSession != null && sessionId != activeSession.sessionId
+ && mParentSessionId != activeSession.sessionId;
+ if (anotherSessionAlreadyInProgress) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+ "There is already in-progress committed staged session "
+ + activeSession.sessionId, null);
+ }
+ }
+
// Read transfers from the original owner stay open, but as the session's data
// cannot be modified anymore, there is no leak of information. For staged sessions,
// further validation is performed by the staging manager.
@@ -1021,6 +1047,13 @@
}
}
+ /** Update the timestamp of when the staged session last changed state */
+ public void markUpdated() {
+ synchronized (mLock) {
+ this.updatedMillis = System.currentTimeMillis();
+ }
+ }
+
@Override
public void transfer(String packageName) {
Preconditions.checkNotNull(packageName);
@@ -1081,13 +1114,7 @@
.write();
}
if (params.isStaged) {
- try {
- mStagingManager.commitSession(this);
- } catch (StagingManager.AlreadyInProgressStagedSessionException e) {
- dispatchSessionFinished(
- PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
- e.getMessage(), null);
- }
+ mStagingManager.commitSession(this);
destroyInternal();
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
return;
@@ -2107,7 +2134,7 @@
private void destroyInternal() {
synchronized (mLock) {
mSealed = true;
- if (!params.isStaged) {
+ if (!params.isStaged || isStagedAndInTerminalState()) {
mDestroyed = true;
}
// Force shut down all bridges
@@ -2217,6 +2244,7 @@
mInstallerPackageName);
writeIntAttribute(out, ATTR_INSTALLER_UID, mInstallerUid);
writeLongAttribute(out, ATTR_CREATED_MILLIS, createdMillis);
+ writeLongAttribute(out, ATTR_UPDATED_MILLIS, updatedMillis);
if (stageDir != null) {
writeStringAttribute(out, ATTR_SESSION_STAGE_DIR,
stageDir.getAbsolutePath());
@@ -2319,6 +2347,7 @@
final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
+ long updatedMillis = readLongAttribute(in, ATTR_UPDATED_MILLIS);
final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index a9126c0..031b5ce 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -107,10 +107,7 @@
}
protected void removeAllDefinedKeySets() {
- final int aliasSize = mKeySetAliases.size();
- for (int i = 0; i < aliasSize; i++) {
- mKeySetAliases.removeAt(i);
- }
+ mKeySetAliases.erase();
}
protected boolean isUsingDefinedKeySets() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e5b6397..ec2ff28 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -160,9 +160,9 @@
import android.content.pm.InstantAppRequest;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.PackageBackwardCompatibility;
import android.content.pm.KeySet;
import android.content.pm.ModuleInfo;
+import android.content.pm.PackageBackwardCompatibility;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageInstaller;
@@ -232,6 +232,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
+import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
@@ -245,6 +246,7 @@
import android.security.KeyStore;
import android.security.SystemKeyStore;
import android.service.pm.PackageServiceDumpProto;
+import android.stats.storage.StorageEnums;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -269,6 +271,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
+import android.util.StatsLog;
import android.util.TimingsTraceLog;
import android.util.Xml;
import android.util.jar.StrictJarFile;
@@ -549,10 +552,21 @@
private static final long DEFAULT_VERIFICATION_TIMEOUT = 10 * 1000;
/**
+ * Timeout duration in milliseconds for enabling package rollback. If we fail to enable
+ * rollback within that period, the install will proceed without rollback enabled.
+ *
+ * <p>If flag value is negative, the default value will be assigned.
+ *
+ * Flag type: {@code long}
+ * Namespace: NAMESPACE_ROLLBACK
+ */
+ private static final String PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS = "enable_rollback_timeout";
+
+ /**
* The default duration to wait for rollback to be enabled in
* milliseconds.
*/
- private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT = 10 * 1000;
+ private static final long DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS = 10 * 1000;
/**
* The default response for package verification timeout.
@@ -1912,6 +1926,15 @@
// Send broadcast package appeared if external for all users
if (isExternal(res.pkg)) {
+ if (!update) {
+ int packageExternalStorageType =
+ getPackageExternalStorageType(res.pkg);
+ // If the package was installed externally, log it.
+ if (packageExternalStorageType != StorageEnums.UNKNOWN) {
+ StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+ packageExternalStorageType, res.pkg.packageName);
+ }
+ }
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.pkg + " is external");
}
@@ -2000,6 +2023,32 @@
}
}
+ /**
+ * Gets the type of the external storage a package is installed on.
+ * @param pkg The package for which to get the external storage type.
+ * @return {@link StorageEnum#TYPE_UNKNOWN} if it is not stored externally or the corresponding
+ * {@link StorageEnum} storage type value if it is.
+ */
+ private int getPackageExternalStorageType(PackageParser.Package pkg) {
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
+ VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+ if (volume != null) {
+ DiskInfo disk = volume.getDisk();
+ if (disk != null) {
+ if (disk.isSd()) {
+ return StorageEnums.SD_CARD;
+ }
+ if (disk.isUsb()) {
+ return StorageEnums.USB;
+ }
+ if (isExternal(pkg)) {
+ return StorageEnums.OTHER;
+ }
+ }
+ }
+ return StorageEnums.UNKNOWN;
+ }
+
private StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
@@ -14716,11 +14765,11 @@
public void onReceive(Context context, Intent intent) {
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
- DeviceConfig.Rollback.NAMESPACE,
- DeviceConfig.Rollback.ENABLE_ROLLBACK_TIMEOUT,
- DEFAULT_ENABLE_ROLLBACK_TIMEOUT);
+ DeviceConfig.NAMESPACE_ROLLBACK,
+ PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
+ DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
- rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT;
+ rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
@@ -20124,21 +20173,20 @@
}
@Override
- public String getContentCaptureServicePackageName() {
- String contentCaptureServiceName =
- mContext.getString(R.string.config_defaultContentCaptureService);
+ public String getSystemCaptionsServicePackageName() {
+ String flattenedSystemCaptionsServiceComponentName =
+ mContext.getString(R.string.config_defaultSystemCaptionsService);
- if (TextUtils.isEmpty(contentCaptureServiceName)) {
+ if (TextUtils.isEmpty(flattenedSystemCaptionsServiceComponentName)) {
return null;
}
- int separatorIndex = contentCaptureServiceName.indexOf("/");
-
- if (separatorIndex < 0) {
+ ComponentName systemCaptionsServiceComponentName =
+ ComponentName.unflattenFromString(flattenedSystemCaptionsServiceComponentName);
+ if (systemCaptionsServiceComponentName == null) {
return null;
}
-
- return contentCaptureServiceName.substring(0, separatorIndex);
+ return systemCaptionsServiceComponentName.getPackageName();
}
public String getIncidentReportApproverPackageName() {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index aced1a2..459de1a 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2693,6 +2693,7 @@
// seinfo - seinfo label for the app (assigned at install time)
// gids - supplementary gids this app launches with
// profileableFromShellFlag - 0 or 1 if the package is profileable from shell.
+ // longVersionCode - integer version of the package.
//
// NOTE: We prefer not to expose all ApplicationInfo flags for now.
//
@@ -2720,6 +2721,8 @@
}
sb.append(" ");
sb.append(ai.isProfileableByShell() ? "1" : "0");
+ sb.append(" ");
+ sb.append(String.valueOf(ai.longVersionCode));
sb.append("\n");
writer.append(sb);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index eced165..9782648 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -99,6 +99,7 @@
private static final String ATTR_ICON_RES_ID = "icon-res";
private static final String ATTR_ICON_RES_NAME = "icon-resname";
private static final String ATTR_BITMAP_PATH = "bitmap-path";
+ private static final String ATTR_LOCUS_ID = "locus-id";
private static final String ATTR_PERSON_NAME = "name";
private static final String ATTR_PERSON_URI = "uri";
@@ -1473,6 +1474,10 @@
ShortcutService.writeAttr(out, ATTR_DISABLED_REASON, si.getDisabledReason());
ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
si.getLastChangedTimestamp());
+ final LocusId locusId = si.getLocusId();
+ if (locusId != null) {
+ ShortcutService.writeAttr(out, ATTR_LOCUS_ID, si.getLocusId().getId());
+ }
if (forBackup) {
// Don't write icon information. Also drop the dynamic flag.
@@ -1612,6 +1617,7 @@
int iconResId;
String iconResName;
String bitmapPath;
+ final String locusIdString;
int backupVersionCode;
ArraySet<String> categories = null;
ArrayList<Person> persons = new ArrayList<>();
@@ -1638,6 +1644,7 @@
iconResId = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES_ID);
iconResName = ShortcutService.parseStringAttribute(parser, ATTR_ICON_RES_NAME);
bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH);
+ locusIdString = ShortcutService.parseStringAttribute(parser, ATTR_LOCUS_ID);
final int outerDepth = parser.getDepth();
int type;
@@ -1703,7 +1710,7 @@
flags |= ShortcutInfo.FLAG_SHADOW;
}
- LocusId locusId = null; // LocusId is not set on XML.
+ final LocusId locusId = locusIdString == null ? null : new LocusId(locusIdString);
return new ShortcutInfo(
userId, id, packageName, activityComponent, /* icon= */ null,
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index fce9bb1..39c731c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -477,23 +477,13 @@
return true;
}
- void commitSession(@NonNull PackageInstallerSession session)
- throws AlreadyInProgressStagedSessionException {
- PackageInstallerSession activeSession = getActiveSession();
- boolean anotherSessionAlreadyInProgress =
- activeSession != null && session.sessionId != activeSession.sessionId;
+ void commitSession(@NonNull PackageInstallerSession session) {
updateStoredSession(session);
- if (anotherSessionAlreadyInProgress) {
- session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "There is already in-progress committed staged session "
- + activeSession.sessionId);
- throw new AlreadyInProgressStagedSessionException(activeSession.sessionId);
- }
mBgHandler.post(() -> preRebootVerification(session));
}
@Nullable
- private PackageInstallerSession getActiveSession() {
+ PackageInstallerSession getActiveSession() {
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession session = mStagedSessions.valueAt(i);
@@ -651,12 +641,4 @@
}
}
}
-
- static final class AlreadyInProgressStagedSessionException extends Exception {
-
- AlreadyInProgressStagedSessionException(int sessionId) {
- super("There is already in-progress committed staged session "
- + sessionId);
- }
- }
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3744f68..316a9c0 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1144,6 +1144,19 @@
}
@Override
+ public String getUserName() {
+ if (!hasManageUsersOrPermission(android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+ throw new SecurityException("You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED "
+ + "permissions to: get user name");
+ }
+ final int userId = UserHandle.getUserId(Binder.getCallingUid());
+ synchronized (mUsersLock) {
+ UserInfo userInfo = userWithName(getUserInfoLU(userId));
+ return userInfo == null ? "" : userInfo.name;
+ }
+ }
+
+ @Override
public long getUserStartRealtime() {
final int userId = UserHandle.getUserId(Binder.getCallingUid());
synchronized (mUsersLock) {
@@ -1299,7 +1312,12 @@
}
}
if (changed) {
- sendUserInfoChangedBroadcast(userId);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ sendUserInfoChangedBroadcast(userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -1324,7 +1342,10 @@
@Override
public ParcelFileDescriptor getUserIcon(int targetUserId) {
- checkManageUsersPermission("get user icon");
+ if (!hasManageUsersOrPermission(android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED)) {
+ throw new SecurityException("You need MANAGE_USERS or GET_ACCOUNTS_PRIVILEGED "
+ + "permissions to: get user icon");
+ }
String iconPath;
synchronized (mPackagesLock) {
UserInfo targetUserInfo = getUserInfoNoChecks(targetUserId);
@@ -1941,15 +1962,23 @@
/**
* @return whether the calling UID is system UID or root's UID or the calling app has the
- * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
- * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or the provided permission.
*/
- private static final boolean hasManageOrCreateUsersPermission() {
+ private static final boolean hasManageUsersOrPermission(String alternativePermission) {
final int callingUid = Binder.getCallingUid();
return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
|| callingUid == Process.ROOT_UID
|| hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)
- || hasPermissionGranted(android.Manifest.permission.CREATE_USERS, callingUid);
+ || hasPermissionGranted(alternativePermission, callingUid);
+ }
+
+ /**
+ * @return whether the calling UID is system UID or root's UID or the calling app has the
+ * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+ * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+ */
+ private static final boolean hasManageOrCreateUsersPermission() {
+ return hasManageUsersOrPermission(android.Manifest.permission.CREATE_USERS);
}
/**
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index f97dd3b..0a17e130 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -704,6 +704,12 @@
TelephonyManager.ACTION_EMERGENCY_ASSISTANCE, userId),
userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+ // STOPSHIP(b/128289173): remove once EmergencyInfo app was replaced.
+ grantSystemFixedPermissionsToSystemPackage(
+ getDefaultSystemHandlerActivityPackage(
+ "com.android.emergency.action.EMERGENCY_ASSISTANCE", userId),
+ userId, CONTACTS_PERMISSIONS, PHONE_PERMISSIONS);
+
// NFC Tag viewer
Intent nfcTagIntent = new Intent(Intent.ACTION_VIEW)
.setType("vnd.android.cursor.item/ndef_msg");
@@ -742,11 +748,11 @@
grantSystemFixedPermissionsToSystemPackage("com.android.sharedstoragebackup", userId,
STORAGE_PERMISSIONS);
- // Content Capture Service
- String contentCaptureServicePackageName =
- mContext.getPackageManager().getContentCaptureServicePackageName();
- if (!TextUtils.isEmpty(contentCaptureServicePackageName)) {
- grantPermissionsToSystemPackage(contentCaptureServicePackageName, userId,
+ // System Captions Service
+ String systemCaptionsServicePackageName =
+ mContext.getPackageManager().getSystemCaptionsServicePackageName();
+ if (!TextUtils.isEmpty(systemCaptionsServicePackageName)) {
+ grantPermissionsToSystemPackage(systemCaptionsServicePackageName, userId,
MICROPHONE_PERMISSIONS);
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 897b885..e36ac23 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -17,14 +17,20 @@
package com.android.server.pm.permission;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.READ_MEDIA_AUDIO;
+import static android.Manifest.permission.READ_MEDIA_IMAGES;
+import static android.Manifest.permission.READ_MEDIA_VIDEO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.permissionToOp;
import static android.app.AppOpsManager.permissionToOpCode;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE;
@@ -1149,6 +1155,8 @@
updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
permissionsState, pkg, updatedUserIds);
+ updatedUserIds = applyLegacyStoragePermissionModel(origPermissions, permissionsState,
+ pkg, updatedUserIds);
setAppOpsLocked(permissionsState, pkg);
}
@@ -1468,6 +1476,179 @@
}
/**
+ * Pre-Q apps use READ/WRITE_EXTERNAL_STORAGE, post-Q apps use READ_MEDIA_AUDIO/VIDEO/IMAGES.
+ *
+ * <p>There is the special case of the grandfathered post-Q app that has all legacy and modern
+ * permissions system-fixed granted. The only way to remove these permissions is to uninstall
+ * the app.
+ *
+ * @param origPs The permission state of the package before the update
+ * @param ps The permissions state of the package
+ * @param pkg The package
+ * @param updatedUserIds The userIds we have already been updated before
+ *
+ * @return The userIds that have been updated
+ *
+ * @see com.android.server.StorageManagerService#applyLegacyStorage()
+ */
+ private @NonNull int[] applyLegacyStoragePermissionModel(@NonNull PermissionsState origPs,
+ @NonNull PermissionsState ps, @NonNull PackageParser.Package pkg,
+ @NonNull int[] updatedUserIds) {
+ AppOpsManagerInternal appOpsManager = LocalServices.getService(AppOpsManagerInternal.class);
+ int[] users = UserManagerService.getInstance().getUserIds();
+
+ boolean isQApp = pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q;
+ boolean isPreMApp = pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M;
+ int appId = getAppId(pkg.applicationInfo.uid);
+
+ int numRequestedPerms = pkg.requestedPermissions.size();
+ for (int i = 0; i < numRequestedPerms; i++) {
+ String perm = pkg.requestedPermissions.get(i);
+
+ boolean isLegacyStoragePermission = false;
+ boolean isModernStoragePermission = false;
+ switch (perm) {
+ case READ_EXTERNAL_STORAGE:
+ case WRITE_EXTERNAL_STORAGE:
+ isLegacyStoragePermission = true;
+ break;
+ case READ_MEDIA_AUDIO:
+ case READ_MEDIA_VIDEO:
+ case READ_MEDIA_IMAGES:
+ isModernStoragePermission = true;
+ break;
+ default:
+ // 'perm' is not a storage permission, skip it
+ continue;
+ }
+
+ BasePermission bp = mSettings.getPermissionLocked(perm);
+
+ for (int userId : users) {
+ boolean useLegacyStoragePermissionModel;
+ if (isQApp) {
+ useLegacyStoragePermissionModel = appOpsManager.checkOperationUnchecked(
+ OP_LEGACY_STORAGE, getUid(userId, appId), pkg.packageName)
+ == MODE_ALLOWED;
+ } else {
+ useLegacyStoragePermissionModel = true;
+ }
+
+ int origCombinedLegacyFlags =
+ origPs.getPermissionFlags(READ_EXTERNAL_STORAGE, userId)
+ | origPs.getPermissionFlags(WRITE_EXTERNAL_STORAGE, userId);
+
+ int origCombinedModernFlags = origPs.getPermissionFlags(READ_MEDIA_AUDIO, userId)
+ | origPs.getPermissionFlags(READ_MEDIA_VIDEO, userId)
+ | origPs.getPermissionFlags(READ_MEDIA_IMAGES, userId);
+
+ boolean oldPermAreLegacyStorageModel =
+ (origCombinedLegacyFlags & FLAG_PERMISSION_HIDDEN) == 0;
+ boolean oldPermAreModernStorageModel =
+ (origCombinedModernFlags & FLAG_PERMISSION_HIDDEN) == 0;
+
+ if (oldPermAreLegacyStorageModel && oldPermAreModernStorageModel) {
+ // This only happens after an platform upgrade from before Q
+ oldPermAreModernStorageModel = false;
+ }
+
+ boolean shouldBeRestricted;
+ boolean shouldBeFixed;
+ boolean shouldBeGranted = false;
+ boolean shouldBeRevoked = false;
+ int userFlags = -1;
+ if (useLegacyStoragePermissionModel) {
+ shouldBeRestricted = isModernStoragePermission;
+ shouldBeFixed = isQApp || isModernStoragePermission;
+
+ if (shouldBeFixed) {
+ userFlags = 0;
+ shouldBeGranted = true;
+ shouldBeRevoked = false;
+ } else if (oldPermAreModernStorageModel) {
+ // Inherit grant state on permission model change
+ userFlags = origCombinedModernFlags;
+
+ shouldBeGranted = origPs.hasRuntimePermission(READ_MEDIA_AUDIO, userId)
+ || origPs.hasRuntimePermission(READ_MEDIA_VIDEO, userId)
+ || origPs.hasRuntimePermission(READ_MEDIA_IMAGES, userId);
+
+ shouldBeRevoked = !shouldBeGranted;
+ }
+ } else {
+ shouldBeRestricted = isLegacyStoragePermission;
+ shouldBeFixed = isLegacyStoragePermission;
+
+ if (shouldBeFixed) {
+ userFlags = 0;
+ shouldBeGranted = true;
+ shouldBeRevoked = false;
+ } else if (oldPermAreLegacyStorageModel) {
+ // Inherit grant state on permission model change
+ userFlags = origCombinedLegacyFlags;
+
+ shouldBeGranted = origPs.hasRuntimePermission(READ_EXTERNAL_STORAGE, userId)
+ || origPs.hasRuntimePermission(WRITE_EXTERNAL_STORAGE, userId);
+
+ if ((origCombinedLegacyFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0
+ && !isPreMApp) {
+ shouldBeGranted = false;
+ }
+
+ shouldBeRevoked = !shouldBeGranted;
+ }
+ }
+
+ // Granted permissions can never be user fixed
+ if (shouldBeGranted & userFlags != -1) {
+ userFlags &= ~FLAG_PERMISSION_USER_FIXED;
+ }
+
+ boolean changed = false;
+ synchronized (mLock) {
+ if (shouldBeGranted) {
+ if (isPreMApp) {
+ setAppOpMode(perm, pkg, userId, MODE_ALLOWED);
+ } else if (!ps.hasRuntimePermission(perm, userId)) {
+ ps.grantRuntimePermission(bp, userId);
+ changed = true;
+ }
+ }
+
+ if (shouldBeRevoked) {
+ if (isPreMApp) {
+ setAppOpMode(perm, pkg, userId, MODE_IGNORED);
+ } else if (ps.hasRuntimePermission(perm, userId)) {
+ ps.revokeRuntimePermission(bp, userId);
+ changed = true;
+ }
+ }
+
+ if (shouldBeFixed) {
+ changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
+ userId, FLAG_PERMISSION_SYSTEM_FIXED, FLAG_PERMISSION_SYSTEM_FIXED);
+ }
+
+ if (userFlags != -1) {
+ changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm),
+ userId, USER_PERMISSION_FLAGS, userFlags);
+ }
+
+ changed |= ps.updatePermissionFlags(mSettings.getPermissionLocked(perm), userId,
+ FLAG_PERMISSION_HIDDEN,
+ shouldBeRestricted ? FLAG_PERMISSION_HIDDEN : 0);
+ }
+
+ if (changed) {
+ updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
+ }
+ }
+ }
+
+ return updatedUserIds;
+ }
+
+ /**
* Fix app-op modes for runtime permissions.
*
* @param permsState The state of the permissions of the package
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 2280d3f..c610ed0 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -19,6 +19,9 @@
},
{
"include-filter": "android.permission.cts.PermissionFlagsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.DualStoragePermissionModelTest"
}
]
},
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5810636..1f89840 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -104,7 +104,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
@@ -918,9 +917,6 @@
mWindowManagerFuncs.onPowerKeyDown(interactive);
- // Abort possibly stuck animations.
- mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
-
// Latch power key state to detect screenshot chord.
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
@@ -1027,6 +1023,11 @@
cancelPendingPowerKeyAction();
if (!handled) {
+ if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == 0) {
+ // Abort possibly stuck animations only when power key up without long press case.
+ mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
+ }
+
// Figure out how to handle the key now that it has been released.
mPowerKeyPressCounter += 1;
@@ -3363,9 +3364,6 @@
*/
void launchHomeFromHotKey(int displayId, final boolean awakenFromDreams,
final boolean respectKeyguard) {
- // Abort possibly stuck animations.
- mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
-
if (respectKeyguard) {
if (isKeyguardShowingAndNotOccluded()) {
// don't launch home if keyguard showing
@@ -5114,6 +5112,7 @@
awakenDreams();
}
+ // Start dock.
Intent dock = createHomeDockIntent();
if (dock != null) {
try {
@@ -5126,21 +5125,9 @@
}
}
- Intent intent;
-
- if (fromHomeKey) {
- intent = new Intent(mHomeIntent);
- intent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, fromHomeKey);
- } else {
- intent = mHomeIntent;
- }
- final Bundle bundle = getLaunchDisplayIdBundle(displayId);
- startActivityAsUser(intent, bundle, UserHandle.CURRENT);
- }
-
- private @Nullable Bundle getLaunchDisplayIdBundle(int displayId) {
- return (displayId == INVALID_DISPLAY) ? null
- : ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle();
+ // Start home.
+ mActivityTaskManagerInternal.startHomeOnDisplay(mCurrentUserId, "startDockOrHome",
+ displayId, fromHomeKey);
}
/**
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index 406cbc1..701e5af 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -269,7 +269,7 @@
*/
@VisibleForTesting
boolean isAttentionServiceSupported() {
- return mAttentionManager.isAttentionServiceSupported();
+ return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported();
}
public void dump(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 1a82858..b81d969 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -486,6 +486,8 @@
log.setType(MetricsEvent.TYPE_OPEN);
log.setSubtype(why);
log.setLatency(interactiveChangeLatency);
+ log.addTaggedData(
+ MetricsEvent.FIELD_SCREEN_WAKE_REASON, mInteractiveChangeReason);
MetricsLogger.action(log);
EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);
mPolicy.finishedWakingUp(why);
@@ -513,6 +515,8 @@
log.setType(MetricsEvent.TYPE_CLOSE);
log.setSubtype(why);
log.setLatency(interactiveChangeLatency);
+ log.addTaggedData(
+ MetricsEvent.FIELD_SCREEN_SLEEP_REASON, mInteractiveChangeReason);
MetricsLogger.action(log);
EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency);
mPolicy.finishedGoingToSleep(why);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 5adcf35..f0e4625 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -115,9 +115,41 @@
public static final int REASON_SETTING_CHANGED = 8;
public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9;
public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10;
- public static final int REASON_STICKY_RESTORE_OFF = 11;
- public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 12;
- public static final int REASON_TIMEOUT = 13;
+ public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11;
+ public static final int REASON_TIMEOUT = 12;
+
+ static String reasonToString(int reason) {
+ switch (reason) {
+ case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON:
+ return "Percentage Auto ON";
+ case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF:
+ return "Percentage Auto OFF";
+ case BatterySaverController.REASON_MANUAL_ON:
+ return "Manual ON";
+ case BatterySaverController.REASON_MANUAL_OFF:
+ return "Manual OFF";
+ case BatterySaverController.REASON_STICKY_RESTORE:
+ return "Sticky restore";
+ case BatterySaverController.REASON_INTERACTIVE_CHANGED:
+ return "Interactivity changed";
+ case BatterySaverController.REASON_POLICY_CHANGED:
+ return "Policy changed";
+ case BatterySaverController.REASON_PLUGGED_IN:
+ return "Plugged in";
+ case BatterySaverController.REASON_SETTING_CHANGED:
+ return "Setting changed";
+ case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON:
+ return "Dynamic Warning Auto ON";
+ case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF:
+ return "Dynamic Warning Auto OFF";
+ case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED:
+ return "Adaptive Power Savings changed";
+ case BatterySaverController.REASON_TIMEOUT:
+ return "timeout";
+ default:
+ return "Unknown reason: " + reason;
+ }
+ }
/**
* Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index af5d40bf..8f2e997 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -15,6 +15,8 @@
*/
package com.android.server.power.batterysaver;
+import static com.android.server.power.batterysaver.BatterySaverController.reasonToString;
+
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -49,6 +51,42 @@
* Do not call out with the lock held. (Settings provider is okay.)
*
* Test: atest com.android.server.power.batterysaver.BatterySaverStateMachineTest
+ *
+ * Current state machine. This can be visualized using Graphviz:
+ <pre>
+
+ digraph {
+ STATE_OFF
+ STATE_MANUAL_ON [label="STATE_MANUAL_ON\nTurned on manually by the user"]
+ STATE_AUTOMATIC_ON [label="STATE_AUTOMATIC_ON\nTurned on automatically by the system"]
+ STATE_OFF_AUTOMATIC_SNOOZED [
+ label="STATE_OFF_AUTOMATIC_SNOOZED\nTurned off manually by the user."
+ + " The system should not turn it back on automatically."
+ ]
+ STATE_PENDING_STICKY_ON [
+ label="STATE_PENDING_STICKY_ON\n"
+ + " Turned on manually by the user and then plugged in. Will turn back on after unplug."
+ ]
+
+ STATE_OFF -> STATE_MANUAL_ON [label="manual"]
+ STATE_OFF -> STATE_AUTOMATIC_ON [label="Auto on AND charge <= auto threshold"]
+
+ STATE_MANUAL_ON -> STATE_OFF [label="manual\nOR\nPlugged & sticky disabled"]
+ STATE_MANUAL_ON -> STATE_PENDING_STICKY_ON [label="Plugged & sticky enabled"]
+
+ STATE_PENDING_STICKY_ON -> STATE_MANUAL_ON [label="Unplugged & sticky enabled"]
+ STATE_PENDING_STICKY_ON -> STATE_OFF [
+ label="Sticky disabled\nOR\nSticky auto off enabled AND charge >= sticky auto off threshold"
+ ]
+
+ STATE_AUTOMATIC_ON -> STATE_OFF [label="Plugged"]
+ STATE_AUTOMATIC_ON -> STATE_OFF_AUTOMATIC_SNOOZED [label="Manual"]
+
+ STATE_OFF_AUTOMATIC_SNOOZED -> STATE_OFF [label="Plug\nOR\nCharge > auto threshold"]
+ STATE_OFF_AUTOMATIC_SNOOZED -> STATE_MANUAL_ON [label="manual"]
+
+ </pre>
+ }
*/
public class BatterySaverStateMachine {
private static final String TAG = "BatterySaverStateMachine";
@@ -60,6 +98,25 @@
private static final long ADAPTIVE_CHANGE_TIMEOUT_MS = 24 * 60 * 60 * 1000L;
+ /** Turn off adaptive battery saver if the device has charged above this level. */
+ private static final int ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL = 80;
+
+ private static final int STATE_OFF = BatterySaverStateMachineProto.STATE_OFF;
+
+ /** Turned on manually by the user. */
+ private static final int STATE_MANUAL_ON = BatterySaverStateMachineProto.STATE_MANUAL_ON;
+
+ /** Turned on automatically by the system. */
+ private static final int STATE_AUTOMATIC_ON = BatterySaverStateMachineProto.STATE_AUTOMATIC_ON;
+
+ /** Turned off manually by the user. The system should not turn it back on automatically. */
+ private static final int STATE_OFF_AUTOMATIC_SNOOZED =
+ BatterySaverStateMachineProto.STATE_OFF_AUTOMATIC_SNOOZED;
+
+ /** Turned on manually by the user and then plugged in. Will turn back on after unplug. */
+ private static final int STATE_PENDING_STICKY_ON =
+ BatterySaverStateMachineProto.STATE_PENDING_STICKY_ON;
+
private final Context mContext;
private final BatterySaverController mBatterySaverController;
@@ -75,6 +132,9 @@
@GuardedBy("mLock")
private boolean mBatteryStatusSet;
+ @GuardedBy("mLock")
+ private int mState;
+
/** Whether the device is connected to any power source. */
@GuardedBy("mLock")
private boolean mIsPowered;
@@ -142,13 +202,6 @@
private boolean mDynamicPowerSavingsBatterySaver;
/**
- * Whether BS has been manually disabled while the battery level is low, in which case we
- * shouldn't auto re-enable it until the battery level is not low.
- */
- @GuardedBy("mLock")
- private boolean mBatterySaverSnoozing;
-
- /**
* Last reason passed to {@link #enableBatterySaverLocked}.
*/
@GuardedBy("mLock")
@@ -181,6 +234,7 @@
mLock = lock;
mContext = context;
mBatterySaverController = batterySaverController;
+ mState = STATE_OFF;
mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
@@ -188,8 +242,36 @@
com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
}
- private boolean isAutoBatterySaverConfiguredLocked() {
- return mSettingBatterySaverTriggerThreshold > 0;
+ /** @return true if the automatic percentage based mode should be used */
+ private boolean isAutomaticModeActiveLocked() {
+ return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
+ && mSettingBatterySaverTriggerThreshold > 0;
+ }
+
+ /**
+ * The returned value won't necessarily make sense if {@link #isAutomaticModeActiveLocked()}
+ * returns {@code false}.
+ *
+ * @return true if the battery level is below automatic's threshold.
+ */
+ private boolean isInAutomaticLowZoneLocked() {
+ return mIsBatteryLevelLow;
+ }
+
+ /** @return true if the dynamic mode should be used */
+ private boolean isDynamicModeActiveLocked() {
+ return mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
+ && mDynamicPowerSavingsBatterySaver;
+ }
+
+ /**
+ * The returned value won't necessarily make sense if {@link #isDynamicModeActiveLocked()}
+ * returns {@code false}.
+ *
+ * @return true if the battery level is below dynamic's threshold.
+ */
+ private boolean isInDynamicLowZoneLocked() {
+ return mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
}
/**
@@ -233,7 +315,14 @@
Settings.Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL),
false, mSettingsObserver, UserHandle.USER_SYSTEM);
+
synchronized (mLock) {
+ final boolean lowPowerModeEnabledSticky = getGlobalSetting(
+ Settings.Global.LOW_POWER_MODE_STICKY, 0) != 0;
+
+ if (lowPowerModeEnabledSticky) {
+ mState = STATE_PENDING_STICKY_ON;
+ }
mBootCompleted = true;
@@ -362,6 +451,8 @@
? "Global.low_power changed to 1" : "Global.low_power changed to 0";
enableBatterySaverLocked(/*enable=*/ batterySaverEnabled, /*manual=*/ true,
BatterySaverController.REASON_SETTING_CHANGED, reason);
+ } else {
+ doAutoBatterySaverLocked();
}
}
@@ -428,17 +519,6 @@
}
}
- @GuardedBy("mLock")
- private boolean isBatteryLowLocked() {
- final boolean percentageLow =
- mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_PERCENTAGE
- && mIsBatteryLevelLow;
- final boolean dynamicPowerSavingsLow =
- mSettingAutomaticBatterySaver == PowerManager.POWER_SAVER_MODE_DYNAMIC
- && mBatteryLevel <= mDynamicPowerSavingsDisableThreshold;
- return percentageLow || dynamicPowerSavingsLow;
- }
-
/**
* Decide whether to auto-start / stop battery saver.
*/
@@ -449,7 +529,6 @@
+ " mSettingsLoaded=" + mSettingsLoaded
+ " mBatteryStatusSet=" + mBatteryStatusSet
+ " mIsBatteryLevelLow=" + mIsBatteryLevelLow
- + " mBatterySaverSnoozing=" + mBatterySaverSnoozing
+ " mIsPowered=" + mIsPowered
+ " mSettingAutomaticBatterySaver=" + mSettingAutomaticBatterySaver
+ " mSettingBatterySaverEnabledSticky=" + mSettingBatterySaverEnabledSticky
@@ -460,66 +539,166 @@
return; // Not fully initialized yet.
}
- if (!isBatteryLowLocked()) {
- updateSnoozingLocked(false, "Battery not low");
- }
+ updateStateLocked(false, false);
+ // Adaptive control.
if (SystemClock.elapsedRealtime() - mLastAdaptiveBatterySaverChangedExternallyElapsed
> ADAPTIVE_CHANGE_TIMEOUT_MS) {
mBatterySaverController.setAdaptivePolicyEnabledLocked(
false, BatterySaverController.REASON_TIMEOUT);
mBatterySaverController.resetAdaptivePolicyLocked(
BatterySaverController.REASON_TIMEOUT);
+ } else if (mIsPowered && mBatteryLevel >= ADAPTIVE_AUTO_DISABLE_BATTERY_LEVEL) {
+ mBatterySaverController.setAdaptivePolicyEnabledLocked(false,
+ BatterySaverController.REASON_PLUGGED_IN);
+ }
+ }
+
+ /**
+ * Update the state machine based on the current settings and battery/charge status.
+ *
+ * @param manual Whether the change was made by the user.
+ * @param enable Whether the user wants to turn battery saver on or off. Is only used if {@param
+ * manual} is true.
+ */
+ @GuardedBy("mLock")
+ private void updateStateLocked(boolean manual, boolean enable) {
+ if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) {
+ return; // Not fully initialized yet.
}
- if (mIsPowered) {
- updateSnoozingLocked(false, "Plugged in");
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
- BatterySaverController.REASON_PLUGGED_IN,
- "Plugged in");
-
- if (mBatteryLevel >= 80 /* Arbitrary level */) {
- mBatterySaverController.setAdaptivePolicyEnabledLocked(
- false, BatterySaverController.REASON_PLUGGED_IN);
+ switch (mState) {
+ case STATE_OFF: {
+ if (!mIsPowered) {
+ if (manual) {
+ if (!enable) {
+ Slog.e(TAG, "Tried to disable BS when it's already OFF");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_ON);
+ mState = STATE_MANUAL_ON;
+ } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+ BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON);
+ mState = STATE_AUTOMATIC_ON;
+ } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ false,
+ BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON);
+ mState = STATE_AUTOMATIC_ON;
+ }
+ }
+ break;
}
- } else if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) {
- if (mSettingBatterySaverStickyAutoDisableEnabled
- && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold) {
- setStickyActive(false);
- } else {
- // Re-enable BS.
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ true,
- BatterySaverController.REASON_STICKY_RESTORE,
- "Sticky restore");
+ case STATE_MANUAL_ON: {
+ if (manual) {
+ if (enable) {
+ Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_OFF);
+ mState = STATE_OFF;
+ } else if (mIsPowered) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_PLUGGED_IN);
+ if (mSettingBatterySaverEnabledSticky
+ && !mBatterySaverStickyBehaviourDisabled) {
+ mState = STATE_PENDING_STICKY_ON;
+ } else {
+ mState = STATE_OFF;
+ }
+ }
+ break;
}
- } else if (mSettingAutomaticBatterySaver
- == PowerManager.POWER_SAVER_MODE_PERCENTAGE
- && isAutoBatterySaverConfiguredLocked()) {
- if (mIsBatteryLevelLow && !mBatterySaverSnoozing) {
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
- BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON,
- "Percentage Auto ON");
- } else {
- // Battery not low
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
- BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF,
- "Percentage Auto OFF");
+ case STATE_AUTOMATIC_ON: {
+ if (mIsPowered) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_PLUGGED_IN);
+ mState = STATE_OFF;
+ } else if (manual) {
+ if (enable) {
+ Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_OFF);
+ // When battery saver is disabled manually (while battery saver is enabled)
+ // when the battery level is low, we "snooze" BS -- i.e. disable auto battery
+ // saver.
+ // We resume auto-BS once the battery level is not low, or the device is
+ // plugged in.
+ mState = STATE_OFF_AUTOMATIC_SNOOZED;
+ } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF);
+ mState = STATE_OFF;
+ } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF);
+ mState = STATE_OFF;
+ } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) {
+ enableBatterySaverLocked(/*enable*/ false, /*manual*/ false,
+ BatterySaverController.REASON_SETTING_CHANGED);
+ mState = STATE_OFF;
+ }
+ break;
}
- } else if (mSettingAutomaticBatterySaver
- == PowerManager.POWER_SAVER_MODE_DYNAMIC) {
- if (mBatteryLevel >= mDynamicPowerSavingsDisableThreshold) {
- enableBatterySaverLocked(/*enable=*/ false, /*manual=*/ false,
- BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF,
- "Dynamic Warning Auto OFF");
- } else if (mDynamicPowerSavingsBatterySaver && !mBatterySaverSnoozing) {
- enableBatterySaverLocked(/*enable=*/ true, /*manual=*/ false,
- BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON,
- "Dynamic Warning Auto ON");
+
+ case STATE_OFF_AUTOMATIC_SNOOZED: {
+ if (manual) {
+ if (!enable) {
+ Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED");
+ return;
+ }
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+ BatterySaverController.REASON_MANUAL_ON);
+ mState = STATE_MANUAL_ON;
+ } else if (mIsPowered // Plugging in resets snooze.
+ || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked())
+ || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked())
+ || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) {
+ mState = STATE_OFF;
+ }
+ break;
}
+
+ case STATE_PENDING_STICKY_ON: {
+ if (manual) {
+ // This shouldn't be possible. We'll only be in this state when the device is
+ // plugged in, so the user shouldn't be able to manually change state.
+ Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON");
+ return;
+ }
+ final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled
+ && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold;
+ final boolean isStickyDisabled =
+ mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky;
+ if (isStickyDisabled || shouldTurnOffSticky) {
+ setStickyActive(false);
+ mState = STATE_OFF;
+ } else if (!mIsPowered) {
+ // Re-enable BS.
+ enableBatterySaverLocked(/*enable*/ true, /*manual*/ true,
+ BatterySaverController.REASON_STICKY_RESTORE);
+ mState = STATE_MANUAL_ON;
+ }
+ break;
+ }
+
+ default:
+ Slog.wtf(TAG, "Unknown state: " + mState);
+ break;
}
- // do nothing if automatic battery saver mode = PERCENTAGE and low warning threshold = 0%
+ }
+
+ @VisibleForTesting
+ int getState() {
+ synchronized (mLock) {
+ return mState;
+ }
}
/**
@@ -533,13 +712,17 @@
Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled);
}
synchronized (mLock) {
- enableBatterySaverLocked(/*enable=*/ enabled, /*manual=*/ true,
- (enabled ? BatterySaverController.REASON_MANUAL_ON
- : BatterySaverController.REASON_MANUAL_OFF),
- (enabled ? "Manual ON" : "Manual OFF"));
+ updateStateLocked(true, enabled);
+ // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and
+ // enabled is false
}
}
+ @GuardedBy("mLock")
+ private void enableBatterySaverLocked(boolean enable, boolean manual, int intReason) {
+ enableBatterySaverLocked(enable, manual, intReason, reasonToString(intReason));
+ }
+
/**
* Actually enable / disable battery saver. Write the new state to the global settings
* and propagate it to {@link #mBatterySaverController}.
@@ -566,20 +749,6 @@
mLastChangedIntReason = intReason;
mLastChangedStrReason = strReason;
- if (manual) {
- if (enable) {
- updateSnoozingLocked(false, "Manual snooze OFF");
- } else {
- // When battery saver is disabled manually (while battery saver is enabled)
- // when the battery level is low, we "snooze" BS -- i.e. disable auto battery saver.
- // We resume auto-BS once the battery level is not low, or the device is plugged in.
- if (mBatterySaverController.isFullEnabled() && isBatteryLowLocked()) {
- updateSnoozingLocked(true, "Manual snooze");
- }
- // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true
- }
- }
-
mSettingBatterySaverEnabled = enable;
putGlobalSetting(Settings.Global.LOW_POWER_MODE, enable ? 1 : 0);
@@ -641,15 +810,6 @@
manager.cancel(DYNAMIC_MODE_NOTIFICATION_ID);
}
- @GuardedBy("mLock")
- private void updateSnoozingLocked(boolean snoozing, String reason) {
- if (mBatterySaverSnoozing == snoozing) {
- return;
- }
- if (DEBUG) Slog.d(TAG, "Snooze: " + (snoozing ? "start" : "stop") + " reason=" + reason);
- mBatterySaverSnoozing = snoozing;
- }
-
private void setStickyActive(boolean active) {
mSettingBatterySaverEnabledSticky = active;
putGlobalSetting(Settings.Global.LOW_POWER_MODE_STICKY,
@@ -684,6 +844,8 @@
pw.print(")");
}
pw.println();
+ pw.print(" mState=");
+ pw.println(mState);
pw.print(" mLastChangedIntReason=");
pw.println(mLastChangedIntReason);
@@ -697,9 +859,6 @@
pw.print(" mBatteryStatusSet=");
pw.println(mBatteryStatusSet);
- pw.print(" mBatterySaverSnoozing=");
- pw.println(mBatterySaverSnoozing);
-
pw.print(" mIsPowered=");
pw.println(mIsPowered);
pw.print(" mBatteryLevel=");
@@ -731,6 +890,7 @@
proto.write(BatterySaverStateMachineProto.ENABLED,
mBatterySaverController.isEnabled());
+ proto.write(BatterySaverStateMachineProto.STATE, mState);
proto.write(BatterySaverStateMachineProto.IS_FULL_ENABLED,
mBatterySaverController.isFullEnabled());
proto.write(BatterySaverStateMachineProto.IS_ADAPTIVE_ENABLED,
@@ -742,8 +902,6 @@
proto.write(BatterySaverStateMachineProto.SETTINGS_LOADED, mSettingsLoaded);
proto.write(BatterySaverStateMachineProto.BATTERY_STATUS_SET, mBatteryStatusSet);
- proto.write(BatterySaverStateMachineProto.BATTERY_SAVER_SNOOZING,
- mBatterySaverSnoozing);
proto.write(BatterySaverStateMachineProto.IS_POWERED, mIsPowered);
proto.write(BatterySaverStateMachineProto.BATTERY_LEVEL, mBatteryLevel);
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 83d18a6..d632749 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -16,6 +16,7 @@
package com.android.server.rollback;
+import android.Manifest;
import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -24,6 +25,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ModuleInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
@@ -42,6 +44,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.util.IntArray;
import android.util.Log;
@@ -220,9 +223,7 @@
@Override
public ParceledListSlice getAvailableRollbacks() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "getAvailableRollbacks");
+ enforceManageRollbacks("getAvailableRollbacks");
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -239,9 +240,7 @@
@Override
public ParceledListSlice<RollbackInfo> getRecentlyExecutedRollbacks() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "getRecentlyExecutedRollbacks");
+ enforceManageRollbacks("getRecentlyCommittedRollbacks");
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -259,9 +258,7 @@
@Override
public void commitRollback(int rollbackId, ParceledListSlice causePackages,
String callerPackageName, IntentSender statusReceiver) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "executeRollback");
+ enforceManageRollbacks("executeRollback");
final int callingUid = Binder.getCallingUid();
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -459,11 +456,8 @@
Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
- // TODO: This call emits the warning "Calling a method in the
- // system process without a qualified user". Fix that.
- // TODO: Limit this to receivers holding the
- // MANAGE_ROLLBACKS permission?
- mContext.sendBroadcast(broadcast);
+ mContext.sendBroadcastAsUser(broadcast, UserHandle.SYSTEM,
+ Manifest.permission.MANAGE_ROLLBACKS);
});
}
);
@@ -484,7 +478,7 @@
@Override
public void reloadPersistedData() {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
"reloadPersistedData");
synchronized (mLock) {
@@ -499,7 +493,7 @@
@Override
public void expireRollbackForPackage(String packageName) {
mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
"expireRollbackForPackage");
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
@@ -535,8 +529,8 @@
private void updateRollbackLifetimeDurationInMillis() {
mRollbackLifetimeDurationInMillis = DeviceConfig.getLong(
- DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS);
if (mRollbackLifetimeDurationInMillis < 0) {
mRollbackLifetimeDurationInMillis = DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS;
@@ -894,12 +888,19 @@
Log.i(TAG, "Enabling rollback for install of " + packageName
+ ", session:" + session.sessionId);
+ String installerPackageName = session.getInstallerPackageName();
+ if (!enableRollbackAllowed(installerPackageName, packageName)) {
+ Log.e(TAG, "Installer " + installerPackageName
+ + " is not allowed to enable rollback on " + packageName);
+ return false;
+ }
+
VersionedPackage newVersion = new VersionedPackage(packageName, newPackage.versionCode);
final boolean isApex = ((installFlags & PackageManager.INSTALL_APEX) != 0);
// Get information about the currently installed package.
PackageManager pm = mContext.getPackageManager();
- PackageInfo pkgInfo = null;
+ final PackageInfo pkgInfo;
try {
pkgInfo = pm.getPackageInfo(packageName, isApex ? PackageManager.MATCH_APEX : 0);
} catch (PackageManager.NameNotFoundException e) {
@@ -1086,6 +1087,44 @@
}
/**
+ * Returns true if the installer is allowed to enable rollback for the
+ * given named package, false otherwise.
+ */
+ private boolean enableRollbackAllowed(String installerPackageName, String packageName) {
+ if (installerPackageName == null) {
+ return false;
+ }
+
+ PackageManager pm = mContext.getPackageManager();
+ boolean manageRollbacksGranted = pm.checkPermission(
+ Manifest.permission.MANAGE_ROLLBACKS,
+ installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+ boolean testManageRollbacksGranted = pm.checkPermission(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
+ installerPackageName) == PackageManager.PERMISSION_GRANTED;
+
+ // For now only allow rollbacks for modules or for testing.
+ return (isModule(packageName) && manageRollbacksGranted)
+ || testManageRollbacksGranted;
+ }
+
+ /**
+ * Returns true if the package name is the name of a module.
+ */
+ private boolean isModule(String packageName) {
+ PackageManager pm = mContext.getPackageManager();
+ final ModuleInfo moduleInfo;
+ try {
+ moduleInfo = pm.getModuleInfo(packageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+
+ return moduleInfo != null;
+ }
+
+ /**
* Gets the version of the package currently installed.
* Returns null if the package is not currently installed.
*/
@@ -1311,4 +1350,15 @@
}
}
}
+
+ private void enforceManageRollbacks(@NonNull String message) {
+ if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+ Manifest.permission.MANAGE_ROLLBACKS))
+ && (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS))) {
+ throw new SecurityException(message + " requires "
+ + Manifest.permission.MANAGE_ROLLBACKS + " or "
+ + Manifest.permission.TEST_MANAGE_ROLLBACKS);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 2b17d19..1800433 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -19,6 +19,8 @@
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.os.Process.getPidsForCommands;
import static android.os.Process.getUidForPid;
+import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
+import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs;
@@ -89,6 +91,7 @@
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.stats.storage.StorageEnums;
import android.telephony.ModemActivityInfo;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -1968,7 +1971,7 @@
pulledData.add(e);
}
- private void pullSDCardInfo(int tagId, long elapsedNanos, long wallClockNanos,
+ private void pullExternalStorageInfo(int tagId, long elapsedNanos, long wallClockNanos,
List<StatsLogEventWrapper> pulledData) {
StorageManager storageManager = mContext.getSystemService(StorageManager.class);
if (storageManager != null) {
@@ -1976,11 +1979,29 @@
for (VolumeInfo vol : volumes) {
final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
final DiskInfo diskInfo = vol.getDisk();
- if (diskInfo != null && diskInfo.isSd()) {
+ if (diskInfo != null) {
if (envState.equals(Environment.MEDIA_MOUNTED)) {
+ // Get the type of the volume, if it is adoptable or portable.
+ int volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__OTHER;
+ if (vol.getType() == TYPE_PUBLIC) {
+ volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PUBLIC;
+ } else if (vol.getType() == TYPE_PRIVATE) {
+ volumeType = StatsLog.EXTERNAL_STORAGE_INFO__VOLUME_TYPE__PRIVATE;
+ }
+ // Get the type of external storage inserted in the device (sd cards,
+ // usb, etc)
+ int externalStorageType;
+ if (diskInfo.isSd()) {
+ externalStorageType = StorageEnums.SD_CARD;
+ } else if (diskInfo.isUsb()) {
+ externalStorageType = StorageEnums.USB;
+ } else {
+ externalStorageType = StorageEnums.OTHER;
+ }
StatsLogEventWrapper e =
new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(vol.getType() + 1);
+ e.writeInt(externalStorageType);
+ e.writeInt(volumeType);
e.writeLong(diskInfo.size);
pulledData.add(e);
}
@@ -2185,8 +2206,8 @@
pullTimeZoneDataInfo(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
- case StatsLog.SDCARD_INFO: {
- pullSDCardInfo(tagId, elapsedNanos, wallClockNanos, ret);
+ case StatsLog.EXTERNAL_STORAGE_INFO: {
+ pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
default:
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index a33b454d..9d6efb4 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -1173,7 +1173,17 @@
}
private void releaseSelfIfNeeded() {
- if (mStacks.isEmpty() && mRemoved) {
+ if (!mRemoved || mDisplayContent == null) {
+ return;
+ }
+
+ final ActivityStack stack = mStacks.size() == 1 ? mStacks.get(0) : null;
+ if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
+ // Release this display if an empty home stack is the only thing left.
+ // Since it is the last stack, this display will be released along with the stack
+ // removal.
+ stack.remove();
+ } else if (mStacks.isEmpty()) {
mDisplayContent.removeIfPossible();
mDisplayContent = null;
mRootActivityContainer.removeChild(this);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ad98970..4c9b80b 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3053,7 +3053,17 @@
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityInNextFocusableStack: " + reason + ", go home");
- return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
+ if (isActivityTypeHome()) {
+ // resumeTopActivityUncheckedLocked has been prevented to run recursively. Post a
+ // runnable to resume home since we are currently in the process of resuming top
+ // activity in home stack.
+ // See {@link #mInResumeTopActivity}.
+ mService.mH.post(
+ () -> mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId));
+ return true;
+ } else {
+ return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
+ }
}
/** Returns the position the input task should be placed in this stack. */
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 9a5ec2a..d7c9bc7 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2453,46 +2453,43 @@
mService.getTaskChangeNotificationController()
.notifyActivityLaunchOnSecondaryDisplayFailed(task.getTaskInfo(),
preferredDisplayId);
- return;
- } else if (!forceNonResizable && handleForcedResizableTask(task,
- FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY)) {
- return;
+ } else if (!forceNonResizable) {
+ handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY);
}
+ // The information about not support secondary display should already be notified, we
+ // don't want to show another message on default display about split-screen. And it may
+ // be the case that a resizable activity is launched on a non-resizable task.
+ return;
}
if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
- // Display a warning toast that we tried to put an app that doesn't support split-screen
- // in split-screen.
- mService.getTaskChangeNotificationController().notifyActivityDismissingDockedStack();
-
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
final ActivityStack dockedStack =
task.getStack().getDisplay().getSplitScreenPrimaryStack();
if (dockedStack != null) {
+ // Display a warning toast that we tried to put an app that doesn't support
+ // split-screen in split-screen.
+ mService.getTaskChangeNotificationController()
+ .notifyActivityDismissingDockedStack();
moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
}
return;
}
- handleForcedResizableTask(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
+ handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN);
}
- /**
- * @return {@code true} if the top activity of the task is forced to be resizable and the user
- * was notified about activity being forced resized.
- */
- private boolean handleForcedResizableTask(TaskRecord task, int reason) {
+ /** Notifies that the top activity of the task is forced to be resizeable. */
+ private void handleForcedResizableTaskIfNeeded(TaskRecord task, int reason) {
final ActivityRecord topActivity = task.getTopActivity();
- if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
- && !topActivity.noDisplay) {
- final String packageName = topActivity.appInfo.packageName;
- mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
- task.taskId, reason, packageName);
- return true;
+ if (topActivity == null || topActivity.noDisplay
+ || !topActivity.isNonResizableOrForcedResizable()) {
+ return;
}
- return false;
+ mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
+ task.taskId, reason, topActivity.appInfo.packageName);
}
void activityRelaunchedLocked(IBinder token) {
@@ -2736,6 +2733,9 @@
if (activityOptions != null) {
activityType = activityOptions.getLaunchActivityType();
windowingMode = activityOptions.getLaunchWindowingMode();
+ if (activityOptions.freezeRecentTasksReordering()) {
+ mRecentTasks.setFreezeTaskListReordering();
+ }
}
if (activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS) {
throw new IllegalArgumentException("startActivityFromRecents: Task "
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 5a20959..b262a00 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -352,6 +352,19 @@
/** @return The intent used to launch the home activity. */
public abstract Intent getHomeIntent();
public abstract boolean startHomeActivity(int userId, String reason);
+ /**
+ * This starts home activity on displays that can have system decorations based on displayId -
+ * Default display always use primary home component.
+ * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves
+ * according to the priorities listed below.
+ * - If default home is not set, always use the secondary home defined in the config.
+ * - Use currently selected primary home activity.
+ * - Use the activity in the same package as currently selected primary home activity.
+ * If there are multiple activities matched, use first one.
+ * - Use the secondary home defined in the config.
+ */
+ public abstract boolean startHomeOnDisplay(int userId, String reason, int displayId,
+ boolean fromHomeKey);
/** Start home activities on all displays that support system decorations. */
public abstract boolean startHomeOnAllDisplays(int userId, String reason);
/** @return true if the given process is the factory test process. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 794a4b8..118eb5b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -748,6 +748,7 @@
mWindowManager.setSupportsPictureInPicture(mSupportsPictureInPicture);
mWindowManager.setSupportsFreeformWindowManagement(mSupportsFreeformWindowManagement);
mWindowManager.setIsPc(isPc);
+ mWindowManager.mRoot.onSettingsRetrieved();
// This happens before any activities are started, so we can change global configuration
// in-place.
updateConfigurationLocked(configuration, null, true);
@@ -6490,6 +6491,13 @@
}
@Override
+ public boolean startHomeOnDisplay(int userId, String reason, int displayId,
+ boolean fromHomeKey) {
+ return mRootActivityContainer.startHomeOnDisplay(userId, reason, displayId,
+ fromHomeKey);
+ }
+
+ @Override
public boolean startHomeOnAllDisplays(int userId, String reason) {
synchronized (mGlobalLock) {
return mRootActivityContainer.startHomeOnAllDisplays(userId, reason);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index af05a27..e053ff3 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -484,6 +484,10 @@
mListeners.add(listener);
}
+ void unregisterListener(AppTransitionListener listener) {
+ mListeners.remove(listener);
+ }
+
public void notifyAppTransitionFinishedLocked(IBinder token) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onAppTransitionFinishedLocked(token);
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index f6326957..75e34fb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
@@ -638,6 +639,39 @@
return transit;
}
+ /**
+ * Identifies whether the current transition occurs within a single task or not. This is used
+ * to determine whether animations should be clipped to the task bounds instead of stack bounds.
+ */
+ @VisibleForTesting
+ boolean isTransitWithinTask(int transit, Task task) {
+ if (task == null
+ || !mDisplayContent.mChangingApps.isEmpty()) {
+ // if there is no task, then we can't constrain to the task.
+ // if anything is changing, it can animate outside its task.
+ return false;
+ }
+ if (!(transit == TRANSIT_ACTIVITY_OPEN
+ || transit == TRANSIT_ACTIVITY_CLOSE
+ || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
+ // only activity-level transitions will be within-task.
+ return false;
+ }
+ // check that all components are in the task.
+ for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
+ Task activityTask = activity.getTask();
+ if (activityTask != task) {
+ return false;
+ }
+ }
+ for (AppWindowToken activity : mDisplayContent.mClosingApps) {
+ if (activity.getTask() != task) {
+ return false;
+ }
+ }
+ return true;
+ }
+
private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
for (int i = apps.size() - 1; i >= 0; i--) {
if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ea3a7d5..955f2e9 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -666,7 +666,7 @@
}
}
- if (isReallyAnimating()) {
+ if (isSelfAnimating()) {
delayed = true;
} else {
@@ -2436,6 +2436,12 @@
getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
+ // Don't animate when the task runs recents animation.
+ final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
+ if (controller != null && controller.isAnimatingTask(getTask())) {
+ return false;
+ }
+
// We animate always if it's not split screen primary, and only some special cases in split
// screen primary because it causes issues with stack clipping when we run an un-minimize
// animation at the same time.
@@ -2705,16 +2711,21 @@
// If the animation needs to be cropped then an animation bounds layer is created as a child
// of the pinned stack or animation layer. The leash is then reparented to this new layer.
if (mNeedsAnimationBoundsLayer) {
- final TaskStack stack = getStack();
- if (stack == null) {
- return;
+ mTmpRect.setEmpty();
+ final Task task = getTask();
+ if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
+ getTransit(), task)) {
+ task.getBounds(mTmpRect);
+ } else {
+ final TaskStack stack = getStack();
+ if (stack == null) {
+ return;
+ }
+ // Set clip rect to stack bounds.
+ stack.getBounds(mTmpRect);
}
mAnimationBoundsLayer = createAnimationBoundsLayer(t);
- // Set clip rect to stack bounds.
- mTmpRect.setEmpty();
- stack.getBounds(mTmpRect);
-
// Crop to stack bounds.
t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3357393..bec72f5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -41,12 +41,14 @@
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_TOP;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
@@ -128,6 +130,7 @@
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
import android.animation.AnimationHandler;
import android.annotation.CallSuper;
@@ -151,6 +154,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -163,6 +167,7 @@
import android.view.DisplayCutout;
import android.view.DisplayInfo;
import android.view.Gravity;
+import android.view.ISystemGestureExclusionListener;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputWindowHandle;
@@ -182,6 +187,8 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ToBooleanFunction;
import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AnimationThread;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.utils.DisplayRotationUtil;
@@ -308,6 +315,10 @@
private DisplayRotation mDisplayRotation;
DisplayFrames mDisplayFrames;
+ private final RemoteCallbackList<ISystemGestureExclusionListener>
+ mSystemGestureExclusionListeners = new RemoteCallbackList<>();
+ private final Region mSystemGestureExclusion = new Region();
+
/**
* For default display it contains real metrics, empty for others.
* @see WindowManagerService#createWatermarkInTransaction()
@@ -887,6 +898,10 @@
mTapDetector = new TaskTapPointerEventListener(mWmService, this);
registerPointerEventListener(mTapDetector);
registerPointerEventListener(mWmService.mMousePositionTracker);
+ if (mWmService.mAtmService.getRecentTasks() != null) {
+ registerPointerEventListener(
+ mWmService.mAtmService.getRecentTasks().getInputListener());
+ }
mDisplayPolicy = new DisplayPolicy(service, this);
mDisplayRotation = new DisplayRotation(service, this);
@@ -2381,6 +2396,27 @@
}
/**
+ * Returns true if the input point is within an app window.
+ */
+ boolean pointWithinAppWindow(int x, int y) {
+ final int[] targetWindowType = {-1};
+ final Consumer fn = PooledLambda.obtainConsumer((w, nonArg) -> {
+ if (targetWindowType[0] != -1) {
+ return;
+ }
+
+ if (w.isOnScreen() && w.isVisibleLw() && w.getFrameLw().contains(x, y)) {
+ targetWindowType[0] = w.mAttrs.type;
+ return;
+ }
+ }, PooledLambda.__(WindowState.class), mTmpRect);
+ forAllWindows(fn, true /* traverseTopToBottom */);
+ ((PooledConsumer) fn).recycle();
+ return FIRST_APPLICATION_WINDOW <= targetWindowType[0]
+ && targetWindowType[0] <= LAST_APPLICATION_WINDOW;
+ }
+
+ /**
* Find the task whose outside touch area (for resizing) (x, y) falls within.
* Returns null if the touch doesn't fall into a resizing area.
*/
@@ -2789,6 +2825,14 @@
mWallpaperController.dump(pw, " ");
pw.println();
+ pw.print("mSystemGestureExclusion=");
+ if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) {
+ pw.println(mSystemGestureExclusion);
+ } else {
+ pw.println("<no lstnrs>");
+ }
+
+ pw.println();
pw.println(prefix + "Application tokens in top down Z order:");
for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
@@ -3255,7 +3299,11 @@
}
private void updateImeParent() {
- final SurfaceControl newParent = computeImeParent();
+ // Force attaching IME to the display when magnifying, or it would be magnified with
+ // target app together.
+ final boolean shouldAttachToDisplay = (mMagnificationSpec != null);
+ final SurfaceControl newParent =
+ shouldAttachToDisplay ? mWindowingLayer : computeImeParent();
if (newParent != null) {
mPendingTransaction.reparent(mImeWindowsContainers.mSurfaceControl, newParent);
scheduleAnimation();
@@ -4670,6 +4718,8 @@
} else {
mMagnificationSpec = null;
}
+ // Re-parent IME's SurfaceControl when MagnificationSpec changed.
+ updateImeParent();
applyMagnificationSpec(getPendingTransaction(), spec);
getPendingTransaction().apply();
@@ -4916,6 +4966,100 @@
}
/**
+ * Updates the display's system gesture exclusion.
+ *
+ * @return true, if the exclusion changed.
+ */
+ boolean updateSystemGestureExclusion() {
+ if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 0) {
+ // No one's interested anyways.
+ return false;
+ }
+
+ final Region systemGestureExclusion = calculateSystemGestureExclusion();
+ try {
+ if (mSystemGestureExclusion.equals(systemGestureExclusion)) {
+ return false;
+ }
+ mSystemGestureExclusion.set(systemGestureExclusion);
+ for (int i = mSystemGestureExclusionListeners.beginBroadcast() - 1; i >= 0; --i) {
+ try {
+ mSystemGestureExclusionListeners.getBroadcastItem(i)
+ .onSystemGestureExclusionChanged(mDisplayId, systemGestureExclusion);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to notify SystemGestureExclusionListener", e);
+ }
+ }
+ mSystemGestureExclusionListeners.finishBroadcast();
+ return true;
+ } finally {
+ systemGestureExclusion.recycle();
+ }
+ }
+
+ @VisibleForTesting
+ Region calculateSystemGestureExclusion() {
+ final Region global = Region.obtain();
+ final Region touchableRegion = Region.obtain();
+ final Region local = Region.obtain();
+
+ // Traverse all windows bottom up to assemble the gesture exclusion rects.
+ // For each window, we only take the rects that fall within its touchable region.
+ forAllWindows(w -> {
+ if (w.cantReceiveTouchInput() || !w.isVisible()
+ || (w.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0) {
+ return;
+ }
+ final boolean modal =
+ (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
+
+ // Only keep the exclusion zones from the windows behind where the current window
+ // isn't touchable.
+ w.getTouchableRegion(touchableRegion);
+ global.op(touchableRegion, Op.DIFFERENCE);
+
+ rectListToRegion(w.getSystemGestureExclusion(), local);
+
+ // Transform to display coordinates
+ local.scale(w.mGlobalScale);
+ final Rect frame = w.getWindowFrames().mFrame;
+ local.translate(frame.left, frame.top);
+
+ // A window can only exclude system gestures where it is actually touchable
+ local.op(touchableRegion, Op.INTERSECT);
+
+ global.op(local, Op.UNION);
+ }, false /* topToBottom */);
+ local.recycle();
+ touchableRegion.recycle();
+ return global;
+ }
+
+ void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
+ mSystemGestureExclusionListeners.register(listener);
+ final boolean changed;
+ if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() == 1) {
+ changed = updateSystemGestureExclusion();
+ } else {
+ changed = false;
+ }
+
+ if (!changed) {
+ // If updateSystemGestureExclusion changed the exclusion, it will already have
+ // notified the listener. Otherwise, we'll do it here.
+ try {
+ listener.onSystemGestureExclusionChanged(mDisplayId, mSystemGestureExclusion);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to notify SystemGestureExclusionListener during register", e);
+ }
+ }
+ }
+
+ void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener) {
+ mSystemGestureExclusionListeners.unregister(listener);
+ }
+
+ /**
* Create a portal window handle for input. This window transports any touch to the display
* indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window.
*
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 4617890..db96847 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -352,6 +352,24 @@
dc.mDisplayScalingDisabled = entry.mForcedScalingMode == FORCE_SCALING_MODE_DISABLED;
}
+ /**
+ * Updates settings for the given display after system features are loaded into window manager
+ * service, e.g. if this device is PC and if this device supports freeform.
+ *
+ * @param dc the given display.
+ * @return {@code true} if any settings for this display has changed; {@code false} if nothing
+ * changed.
+ */
+ boolean updateSettingsForDisplay(DisplayContent dc) {
+ if (dc.getWindowingMode() != getWindowingModeLocked(dc)) {
+ // For the time being the only thing that may change is windowing mode, so just update
+ // that.
+ dc.setWindowingMode(getWindowingModeLocked(dc));
+ return true;
+ }
+ return false;
+ }
+
private void readSettings() {
FileInputStream stream;
try {
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index a667d67..716e4ef 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -73,17 +73,6 @@
return mDragState != null && !mDragState.isClosing();
}
- void showInputSurface(SurfaceControl.Transaction t, int displayId) {
- mDragState.showInputSurface(t, displayId);
- }
-
- void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
- if (mDragState != null) {
- // TODO: Are we guaranteed to get here?
- mDragState.hideInputSurface(t, displayId);
- }
- }
-
void registerCallback(IDragDropCallback callback) {
Preconditions.checkNotNull(callback);
mCallback.set(callback);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 2b2231a..c438966 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -120,7 +120,7 @@
// A surface used to catch input events for the drag-and-drop operation.
SurfaceControl mInputSurface;
- private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private final SurfaceControl.Transaction mTransaction;
private final Rect mTmpClipRect = new Rect();
@@ -140,31 +140,24 @@
mFlags = flags;
mLocalWin = localWin;
mNotifiedWindows = new ArrayList<WindowState>();
-
+ mTransaction = service.mTransactionFactory.make();
}
boolean isClosing() {
return mIsClosing;
}
- void hideInputSurface(SurfaceControl.Transaction t, int displayId) {
- if (displayId != mDisplayContent.getDisplayId()) {
- return;
- }
-
+ private void hideInputSurface() {
if (mInputSurface != null) {
- t.hide(mInputSurface);
+ mTransaction.hide(mInputSurface).apply();
}
}
- void showInputSurface(SurfaceControl.Transaction t, int displayId) {
- if (displayId != mDisplayContent.getDisplayId()) {
- return;
- }
-
+ private void showInputSurface() {
if (mInputSurface == null) {
- mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId)
- .getSession()).setContainerLayer()
+ mInputSurface = mService.makeSurfaceBuilder(
+ mService.mRoot.getDisplayContent(mDisplayContent.getDisplayId()).getSession())
+ .setContainerLayer()
.setName("Drag and Drop Input Consumer").build();
}
final InputWindowHandle h = getInputWindowHandle();
@@ -174,14 +167,16 @@
return;
}
- t.show(mInputSurface);
- t.setInputWindowInfo(mInputSurface, h);
- t.setLayer(mInputSurface, Integer.MAX_VALUE);
+ mTransaction.show(mInputSurface);
+ mTransaction.setInputWindowInfo(mInputSurface, h);
+ mTransaction.setLayer(mInputSurface, Integer.MAX_VALUE);
mTmpClipRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
- t.setWindowCrop(mInputSurface, mTmpClipRect);
- t.transferTouchFocus(mTransferTouchFromToken, h.token);
+ mTransaction.setWindowCrop(mInputSurface, mTmpClipRect);
+ mTransaction.transferTouchFocus(mTransferTouchFromToken, h.token);
mTransferTouchFromToken = null;
+
+ mTransaction.apply();
}
/**
@@ -199,9 +194,10 @@
mDragDropController.sendHandlerMessage(
MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
mInputInterceptor = null;
- mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
}
+ hideInputSurface();
+
// Send drag end broadcast if drag start has been sent.
if (mDragInProgress) {
final int myPid = Process.myPid();
@@ -352,7 +348,7 @@
Slog.e(TAG_WM, "Duplicate register of drag input channel");
} else {
mInputInterceptor = new InputInterceptor(display);
- mDisplayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
+ showInputSurface();
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 2a9c2b0..5669451 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -25,7 +25,6 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
@@ -129,15 +128,6 @@
// If there's a drag in flight, provide a pseudo-window to catch drag input
final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
- if (inDrag) {
- if (DEBUG_DRAG) {
- Log.d(TAG_WM, "Inserting drag window");
- }
- mService.mDragDropController.showInputSurface(mInputTransaction, mDisplayId);
- } else {
- mService.mDragDropController.hideInputSurface(mInputTransaction, mDisplayId);
- }
-
final boolean inPositioning =
mService.mTaskPositioningController.isPositioningLocked();
if (inPositioning) {
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 8c8b05f..72a1a2f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -269,7 +269,8 @@
* @return True if we may show an activity while Keyguard is occluded, false otherwise.
*/
boolean canShowWhileOccluded(boolean dismissKeyguard, boolean showWhenLocked) {
- return showWhenLocked || dismissKeyguard && !mWindowManager.isKeyguardSecure();
+ return showWhenLocked || dismissKeyguard
+ && !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
}
private void visibilitiesUpdated() {
@@ -317,7 +318,7 @@
// We only allow dismissing Keyguard via the flag when Keyguard is secure for legacy
// reasons, because that's how apps used to dismiss Keyguard in the secure case. In the
// insecure case, we actually show it on top of the lockscreen. See #canShowWhileOccluded.
- if (!mWindowManager.isKeyguardSecure()) {
+ if (!mWindowManager.isKeyguardSecure(mService.getCurrentUserId())) {
return;
}
@@ -345,7 +346,8 @@
* @return true if Keyguard can be currently dismissed without entering credentials.
*/
boolean canDismissKeyguard() {
- return mWindowManager.isKeyguardTrusted() || !mWindowManager.isKeyguardSecure();
+ return mWindowManager.isKeyguardTrusted()
+ || !mWindowManager.isKeyguardSecure(mService.getCurrentUserId());
}
private int resolveOccludeTransit() {
@@ -487,7 +489,8 @@
}
if (lastDismissActivity != mDismissingKeyguardActivity && !mOccluded
&& mDismissingKeyguardActivity != null
- && controller.mWindowManager.isKeyguardSecure()) {
+ && controller.mWindowManager.isKeyguardSecure(
+ controller.mService.getCurrentUserId())) {
mRequestDismissKeyguard = true;
}
}
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index e6e6275..2411e00 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -762,7 +762,7 @@
} else {
// If keyguard is not secure and it is locked, dismiss the keyguard before
// disabling it, which avoids the platform to think the keyguard is still on.
- if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure()) {
+ if (mWindowManager.isKeyguardLocked() && !mWindowManager.isKeyguardSecure(userId)) {
mPendingDisableFromDismiss = userId;
mWindowManager.dismissKeyguard(new IKeyguardDismissCallback.Stub() {
@Override
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 0480d43..d69ae3d 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -60,6 +60,7 @@
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -67,8 +68,11 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.view.MotionEvent;
+import android.view.WindowManagerPolicyConstants.PointerEventListener;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
import com.google.android.collect.Sets;
@@ -109,8 +113,11 @@
private static final int DEFAULT_INITIAL_CAPACITY = 5;
- // Whether or not to move all affiliated tasks to the front when one of the tasks is launched
- private static final boolean MOVE_AFFILIATED_TASKS_TO_FRONT = false;
+ // The duration of time after freezing the recent tasks list where getRecentTasks() will return
+ // a stable ordering of the tasks. Upon the next call to getRecentTasks() beyond this duration,
+ // the task list will be unfrozen and committed (the current top task will be moved to the
+ // front of the list)
+ private static final long FREEZE_TASK_LIST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
// Comparator to sort by taskId
private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
@@ -174,12 +181,45 @@
private int mMaxNumVisibleTasks;
private long mActiveTasksSessionDurationMs;
+ // When set, the task list will not be reordered as tasks within the list are moved to the
+ // front. Newly created tasks, or tasks that are removed from the list will continue to change
+ // the list. This does not affect affiliated tasks.
+ private boolean mFreezeTaskListReordering;
+ private long mFreezeTaskListReorderingTime;
+ private long mFreezeTaskListTimeoutMs = FREEZE_TASK_LIST_TIMEOUT_MS;
+
// Mainly to avoid object recreation on multiple calls.
private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>();
private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
+ // TODO(b/127498985): This is currently a rough heuristic for interaction inside an app
+ private final PointerEventListener mListener = new PointerEventListener() {
+ @Override
+ public void onPointerEvent(MotionEvent ev) {
+ if (!mFreezeTaskListReordering || ev.getAction() != MotionEvent.ACTION_DOWN) {
+ // Skip if we aren't freezing or starting a gesture
+ return;
+ }
+ int displayId = ev.getDisplayId();
+ int x = (int) ev.getX();
+ int y = (int) ev.getY();
+ mService.mH.post(PooledLambda.obtainRunnable((nonArg) -> {
+ synchronized (mService.mGlobalLock) {
+ // Unfreeze the task list once we touch down in a task
+ final RootActivityContainer rac = mService.mRootActivityContainer;
+ final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
+ if (dc.pointWithinAppWindow(x, y)) {
+ final ActivityStack stack = mService.getTopDisplayFocusedStack();
+ final TaskRecord topTask = stack != null ? stack.topTask() : null;
+ resetFreezeTaskListReordering(topTask);
+ }
+ }
+ }, null).recycleOnUse());
+ }
+ };
+
@VisibleForTesting
RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) {
mService = service;
@@ -214,6 +254,73 @@
mGlobalMaxNumTasks = globalMaxNumTasks;
}
+ @VisibleForTesting
+ void setFreezeTaskListTimeoutParams(long reorderingTime, long timeoutMs) {
+ mFreezeTaskListReorderingTime = reorderingTime;
+ mFreezeTaskListTimeoutMs = timeoutMs;
+ }
+
+ PointerEventListener getInputListener() {
+ return mListener;
+ }
+
+ /**
+ * Freezes the current recent task list order until either a user interaction with the current
+ * app, or a timeout occurs.
+ */
+ void setFreezeTaskListReordering() {
+ // Always update the reordering time when this is called to ensure that the timeout
+ // is reset
+ mFreezeTaskListReordering = true;
+ mFreezeTaskListReorderingTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Commits the frozen recent task list order, moving the provided {@param topTask} to the
+ * front of the list.
+ */
+ void resetFreezeTaskListReordering(TaskRecord topTask) {
+ if (!mFreezeTaskListReordering) {
+ return;
+ }
+
+ // Once we end freezing the task list, reset the existing task order to the stable state
+ mFreezeTaskListReordering = false;
+
+ // If the top task is provided, then restore the top task to the front of the list
+ if (topTask != null) {
+ mTasks.remove(topTask);
+ mTasks.add(0, topTask);
+ }
+
+ // Resume trimming tasks
+ trimInactiveRecentTasks();
+ }
+
+ /**
+ * Resets the frozen recent task list order if the timeout has passed. This should be called
+ * before we need to iterate the task list in order (either for purposes of returning the list
+ * to SystemUI or if we need to trim tasks in order)
+ */
+ void resetFreezeTaskListReorderingOnTimeout() {
+ // Unfreeze the recent task list if the time heuristic has passed
+ if (mFreezeTaskListReorderingTime
+ > (SystemClock.elapsedRealtime() - mFreezeTaskListTimeoutMs)) {
+ return;
+ }
+
+ final ActivityStack focusedStack = mService.getTopDisplayFocusedStack();
+ final TaskRecord topTask = focusedStack != null
+ ? focusedStack.topTask()
+ : null;
+ resetFreezeTaskListReordering(topTask);
+ }
+
+ @VisibleForTesting
+ boolean isFreezeTaskListReorderingSet() {
+ return mFreezeTaskListReordering;
+ }
+
/**
* Loads the parameters from the system resources.
*/
@@ -351,7 +458,8 @@
}
Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
- mTasks.addAll(mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks));
+ List<TaskRecord> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+ mTasks.addAll(tasks);
cleanupLocked(userId);
mUsersWithRecentsLoaded.put(userId, true);
@@ -746,11 +854,10 @@
getDetailedTasks, userId, callingUid));
}
-
/**
* @return the list of recent tasks for presentation.
*/
- ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
+ private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
boolean getTasksAllowed, boolean getDetailedTasks, int userId, int callingUid) {
final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
@@ -763,6 +870,9 @@
final Set<Integer> includedUsers = getProfileIds(userId);
includedUsers.add(Integer.valueOf(userId));
+ // Check if the frozen task list has timed out
+ resetFreezeTaskListReorderingOnTimeout();
+
final ArrayList<ActivityManager.RecentTaskInfo> res = new ArrayList<>();
final int size = mTasks.size();
int numVisibleTasks = 0;
@@ -946,24 +1056,20 @@
if (task.inRecents) {
int taskIndex = mTasks.indexOf(task);
if (taskIndex >= 0) {
- if (!isAffiliated || !MOVE_AFFILIATED_TASKS_TO_FRONT) {
- // Simple case: this is not an affiliated task, so we just move it to the front.
- mTasks.remove(taskIndex);
- mTasks.add(0, task);
- notifyTaskPersisterLocked(task, false);
- if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
- + " from " + taskIndex);
- return;
- } else {
- // More complicated: need to keep all affiliated tasks together.
- if (moveAffiliatedTasksToFront(task, taskIndex)) {
- // All went well.
- return;
- }
+ if (!isAffiliated) {
+ if (!mFreezeTaskListReordering) {
+ // Simple case: this is not an affiliated task, so we just move it to the
+ // front unless overridden by the provided activity options
+ mTasks.remove(taskIndex);
+ mTasks.add(0, task);
- // Uh oh... something bad in the affiliation chain, try to rebuild
- // everything and then go through our general path of adding a new task.
- needAffiliationFix = true;
+ if (DEBUG_RECENTS) {
+ Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
+ + " from " + taskIndex);
+ }
+ }
+ notifyTaskPersisterLocked(task, false);
+ return;
}
} else {
Slog.wtf(TAG, "Task with inRecent not in recents: " + task);
@@ -1063,6 +1169,11 @@
* Trims the recents task list to the global max number of recents.
*/
private void trimInactiveRecentTasks() {
+ if (mFreezeTaskListReordering) {
+ // Defer trimming inactive recent tasks until we are unfrozen
+ return;
+ }
+
int recentsCount = mTasks.size();
// Remove from the end of the list until we reach the max number of recents
@@ -1086,7 +1197,7 @@
+ " quiet=" + mTmpQuietProfileUserIds.get(userId));
}
- // Remove any inactive tasks, calculate the latest set of visible tasks
+ // Remove any inactive tasks, calculate the latest set of visible tasks.
int numVisibleTasks = 0;
for (int i = 0; i < mTasks.size();) {
final TaskRecord task = mTasks.get(i);
@@ -1300,6 +1411,11 @@
* list (if any).
*/
private int findRemoveIndexForAddTask(TaskRecord task) {
+ if (mFreezeTaskListReordering) {
+ // Defer removing tasks due to the addition of new tasks until the task list is unfrozen
+ return -1;
+ }
+
final int recentsCount = mTasks.size();
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
@@ -1536,6 +1652,9 @@
pw.println("ACTIVITY MANAGER RECENT TASKS (dumpsys activity recents)");
pw.println("mRecentsUid=" + mRecentsUid);
pw.println("mRecentsComponent=" + mRecentsComponent);
+ pw.println("mFreezeTaskListReordering=" + mFreezeTaskListReordering);
+ pw.println("mFreezeTaskListReorderingTime (time since)="
+ + (SystemClock.elapsedRealtime() - mFreezeTaskListReorderingTime) + "ms");
if (mTasks.isEmpty()) {
return;
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index cb9cbd6..f1560d9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -31,6 +31,7 @@
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
@@ -59,7 +60,7 @@
class RecentsAnimation implements RecentsAnimationCallbacks,
ActivityDisplay.OnStackOrderChangedListener {
private static final String TAG = RecentsAnimation.class.getSimpleName();
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = DEBUG_RECENTS_ANIMATIONS;
private final ActivityTaskManagerService mService;
private final ActivityStackSupervisor mStackSupervisor;
@@ -395,11 +396,23 @@
// The stack is not visible, so ignore this change
return;
}
+ final RecentsAnimationController controller =
+ mWindowManager.getRecentsAnimationController();
- // If the activity display stack order changes, cancel any running recents animation in
- // place
- mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE,
- "stackOrderChanged");
+ // Cancel running recents animation and screenshot previous task when the next
+ // transition starts in below cases:
+ // 1) The next launching task is not in recents animation task.
+ // 2) The next task is home activity. (i.e. pressing home key to back home in recents).
+ if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
+ || controller.isTargetApp(stack.getTopActivity().mAppWindowToken))
+ && controller.shouldCancelWithDeferredScreenshot()) {
+ controller.cancelOnNextTransitionStart();
+ } else {
+ // Just cancel directly to unleash from launcher when the next launching task is the
+ // current top task.
+ mWindowManager.cancelRecentsAnimationSynchronously(REORDER_KEEP_IN_PLACE,
+ "stackOrderChanged");
+ }
}
/**
@@ -407,7 +420,7 @@
*/
private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) {
try {
- recentsAnimationRunner.onAnimationCanceled();
+ recentsAnimationRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation before start", e);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 105ff06..26df832 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -29,6 +29,7 @@
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
+import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
import android.annotation.IntDef;
import android.app.ActivityManager.TaskSnapshot;
@@ -92,6 +93,8 @@
private final Runnable mFailsafeRunnable = () ->
cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
+ final Object mLock = new Object();
+
// The recents component app token that is shown behind the visibile tasks
private AppWindowToken mTargetAppToken;
private int mTargetActivityType;
@@ -117,6 +120,27 @@
private boolean mLinkedToDeathOfRunner;
+ private boolean mCancelWithDeferredScreenshot;
+
+ private boolean mCancelOnNextTransitionStart;
+
+ /**
+ * Animates the screenshot of task that used to be controlled by RecentsAnimation.
+ * @see {@link #cancelOnNextTransitionStart}
+ */
+ SurfaceAnimator mRecentScreenshotAnimator;
+
+ final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
+ @Override
+ public int onAppTransitionStartingLocked(int transit, long duration,
+ long statusBarAnimationStartTime, long statusBarAnimationDuration) {
+ onTransitionStart();
+ mService.mRoot.getDisplayContent(mDisplayId).mAppTransition
+ .unregisterListener(this);
+ return 0;
+ }
+ };
+
public interface RecentsAnimationCallbacks {
void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously);
}
@@ -245,6 +269,23 @@
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public void setCancelWithDeferredScreenshot(boolean screenshot) {
+ synchronized (mLock) {
+ setCancelWithDeferredScreenshotLocked(screenshot);
+ }
+ }
+
+ @Override
+ public void cleanupScreenshot() {
+ synchronized (mLock) {
+ if (mRecentScreenshotAnimator != null) {
+ mRecentScreenshotAnimator.cancelAnimation();
+ mRecentScreenshotAnimator = null;
+ }
+ }
+ }
};
/**
@@ -273,6 +314,7 @@
@VisibleForTesting
void initialize(DisplayContent dc, int targetActivityType, SparseBooleanArray recentTaskIds) {
mTargetActivityType = targetActivityType;
+ dc.mAppTransition.registerListenerLocked(mAppTransitionListener);
// Make leashes for each of the visible/target tasks and add it to the recents animation to
// be started
@@ -416,15 +458,20 @@
}
void cancelAnimation(@ReorderMode int reorderMode, String reason) {
- cancelAnimation(reorderMode, false /* runSynchronously */, reason);
+ cancelAnimation(reorderMode, false /* runSynchronously */, false /*screenshot */, reason);
}
void cancelAnimationSynchronously(@ReorderMode int reorderMode, String reason) {
- cancelAnimation(reorderMode, true /* runSynchronously */, reason);
+ cancelAnimation(reorderMode, true /* runSynchronously */, false /* screenshot */, reason);
+ }
+
+ void cancelAnimationWithScreenShot() {
+ cancelAnimation(REORDER_KEEP_IN_PLACE, true /* sync */, true /* screenshot */,
+ "stackOrderChanged");
}
private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
- String reason) {
+ boolean screenshot, String reason) {
if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason
+ " runSynchronously=" + runSynchronously);
synchronized (mService.getWindowManagerLock()) {
@@ -435,14 +482,67 @@
mService.mH.removeCallbacks(mFailsafeRunnable);
mCanceled = true;
try {
- mRunner.onAnimationCanceled();
+ if (screenshot) {
+ // Screen shot previous task when next task starts transition.
+ final Task task = mPendingAnimations.get(0).mTask;
+ screenshotRecentTask(task, reorderMode, runSynchronously);
+ mRunner.onAnimationCanceled(true /* deferredWithScreenshot */);
+ return;
+ }
+ mRunner.onAnimationCanceled(false /* deferredWithScreenshot */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to cancel recents animation", e);
}
+ // Clean up and return to the previous app
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+ }
+ }
+
+ /**
+ * Cancel recents animation when the next app transition starts.
+ * <p>
+ * When we cancel the recents animation due to a stack order change, we can't just cancel it
+ * immediately as it would lead to a flicker in Launcher if we just remove the task from the
+ * leash. Instead we screenshot the previous task and replace the child of the leash with the
+ * screenshot, so that Launcher can still control the leash lifecycle & make the next app
+ * transition animate smoothly without flickering.
+ */
+ void cancelOnNextTransitionStart() {
+ mCancelOnNextTransitionStart = true;
+ }
+
+ void setCancelWithDeferredScreenshotLocked(boolean screenshot) {
+ mCancelWithDeferredScreenshot = screenshot;
+ }
+
+ boolean shouldCancelWithDeferredScreenshot() {
+ return mCancelWithDeferredScreenshot;
+ }
+
+ void onTransitionStart() {
+ if (mCanceled) {
+ return;
}
- // Clean up and return to the previous app
- mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+ if (mCancelOnNextTransitionStart) {
+ mCancelOnNextTransitionStart = false;
+ cancelAnimationWithScreenShot();
+ }
+ }
+
+ void screenshotRecentTask(Task task, @ReorderMode int reorderMode, boolean runSynchronously) {
+ final TaskScreenshotAnimatable animatable = TaskScreenshotAnimatable.create(task);
+ if (animatable != null) {
+ mRecentScreenshotAnimator = new SurfaceAnimator(
+ animatable,
+ () -> {
+ if (DEBUG_RECENTS_ANIMATIONS) {
+ Slog.d(TAG, "mRecentScreenshotAnimator finish");
+ }
+ mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+ }, mService);
+ mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
+ }
}
void cleanupAnimation(@ReorderMode int reorderMode) {
@@ -465,6 +565,12 @@
mRunner = null;
mCanceled = true;
+ // Make sure previous animator has cleaned-up.
+ if (mRecentScreenshotAnimator != null) {
+ mRecentScreenshotAnimator.cancelAnimation();
+ mRecentScreenshotAnimator = null;
+ }
+
// Update the input windows after the animation is complete
final InputMonitor inputMonitor =
mService.mRoot.getDisplayContent(mDisplayId).getInputMonitor();
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index f964b57..24cf7f1 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -114,6 +114,7 @@
import com.android.server.am.ActivityManagerService;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.UserState;
+import com.android.server.policy.WindowManagerPolicy;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -345,6 +346,10 @@
}
}
+ boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+ return startHomeOnDisplay(userId, reason, displayId, false /*fromHomeKey*/);
+ }
+
/**
* This starts home activity on displays that can have system decorations based on displayId -
* Default display always use primary home component.
@@ -356,7 +361,12 @@
* If there are multiple activities matched, use first one.
* - Use the secondary home defined in the config.
*/
- boolean startHomeOnDisplay(int userId, String reason, int displayId) {
+ boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean fromHomeKey) {
+ // Fallback to top focused display if the displayId is invalid.
+ if (displayId == INVALID_DISPLAY) {
+ displayId = getTopDisplayFocusedStack().mDisplayId;
+ }
+
Intent homeIntent;
ActivityInfo aInfo;
if (displayId == DEFAULT_DISPLAY) {
@@ -380,6 +390,10 @@
// Updates the home component of the intent.
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
+ // Updates the extra information of the intent.
+ if (fromHomeKey) {
+ homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
+ }
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index db7613a..ed5f665 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -245,6 +245,34 @@
return dc;
}
+ /**
+ * Called when DisplayWindowSettings values may change.
+ */
+ void onSettingsRetrieved() {
+ final int numDisplays = mChildren.size();
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mChildren.get(displayNdx);
+ final boolean changed = mWmService.mDisplayWindowSettings.updateSettingsForDisplay(
+ displayContent);
+ if (!changed) {
+ continue;
+ }
+
+ displayContent.initializeDisplayOverrideConfiguration();
+ mWmService.reconfigureDisplayLocked(displayContent);
+
+ // We need to update global configuration as well if config of default display has
+ // changed. Do it inline because ATMS#retrieveSettings() will soon update the
+ // configuration inline, which will overwrite the new windowing mode.
+ if (displayContent.isDefaultDisplay) {
+ final Configuration newConfig = mWmService.computeNewConfiguration(
+ displayContent.getDisplayId());
+ mWmService.mAtmService.updateConfigurationLocked(newConfig, null /* starting */,
+ false /* initLocale */);
+ }
+ }
+ }
+
boolean isLayoutNeeded() {
final int numDisplays = mChildren.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
@@ -654,6 +682,7 @@
// Finally update all input windows now that the window changes have stabilized.
forAllDisplays(dc -> {
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
+ dc.updateSystemGestureExclusion();
});
mWmService.setHoldScreenLocked(mHoldScreen);
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index dc8c7b7..9b634f9 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -57,6 +57,7 @@
import java.io.PrintWriter;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -314,6 +315,16 @@
}
}
+ @Override
+ public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mService.reportSystemGestureExclusionChanged(this, window, exclusionRects);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void actionOnWallpaper(IBinder window,
BiConsumer<WallpaperController, WindowState> action) {
final WindowState windowState = mService.windowForClientLocked(this, window, true);
diff --git a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index bdb76c2..bd4e542 100644
--- a/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -83,7 +83,12 @@
}
public void systemReady() {
- mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler);
+ // GestureDetector records statistics about gesture classification events to inform gesture
+ // usage trends. SystemGesturesPointerEventListener creates a lot of noise in these
+ // statistics because it passes every touch event though a GestureDetector. By creating an
+ // anonymous subclass of GestureDetector, these statistics will be recorded with a unique
+ // source name that can be filtered.
+ mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler) {};
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
new file mode 100644
index 0000000..e0d85e8
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskScreenshotAnimatable.java
@@ -0,0 +1,124 @@
+/*
+ * 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.wm;
+
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
+
+import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+/**
+ * Class used by {@link RecentsAnimationController} to create a surface control with taking
+ * screenshot of task when canceling recents animation.
+ *
+ * @see {@link RecentsAnimationController#cancelOnNextTransitionStart}
+ */
+class TaskScreenshotAnimatable implements SurfaceAnimator.Animatable {
+ private static final String TAG = "TaskScreenshotAnim";
+ private Task mTask;
+ private SurfaceControl mSurfaceControl;
+ private int mWidth;
+ private int mHeight;
+
+ public static TaskScreenshotAnimatable create(Task task) {
+ return new TaskScreenshotAnimatable(task, getBufferFromTask(task));
+ }
+
+ private static GraphicBuffer getBufferFromTask(Task task) {
+ if (task == null) {
+ return null;
+ }
+ final Rect tmpRect = task.getBounds();
+ tmpRect.offset(0, 0);
+ return SurfaceControl.captureLayers(
+ task.getSurfaceControl().getHandle(), tmpRect, 1f);
+ }
+
+ private TaskScreenshotAnimatable(Task task, GraphicBuffer buffer) {
+ mTask = task;
+ mWidth = (buffer != null) ? buffer.getWidth() : 1;
+ mHeight = (buffer != null) ? buffer.getHeight() : 1;
+ if (DEBUG_RECENTS_ANIMATIONS) {
+ Slog.d(TAG, "Creating TaskScreenshotAnimatable: task: " + task
+ + "width: " + mWidth + "height: " + mHeight);
+ }
+ mSurfaceControl = new SurfaceControl.Builder(new SurfaceSession())
+ .setName("RecentTaskScreenshotSurface")
+ .setBufferSize(mWidth, mHeight)
+ .build();
+ if (buffer != null) {
+ final Surface surface = new Surface();
+ surface.copyFrom(mSurfaceControl);
+ surface.attachAndQueueBuffer(buffer);
+ surface.release();
+ }
+ getPendingTransaction().show(mSurfaceControl);
+ }
+
+ @Override
+ public SurfaceControl.Transaction getPendingTransaction() {
+ return mTask.mPendingTransaction;
+ }
+
+ @Override
+ public void commitPendingTransaction() {
+ mTask.commitPendingTransaction();
+ }
+
+ @Override
+ public void onAnimationLeashCreated(SurfaceControl.Transaction t, SurfaceControl leash) {
+ t.setLayer(leash, 1);
+ }
+
+ @Override
+ public void onAnimationLeashDestroyed(SurfaceControl.Transaction t) {
+ t.remove(mSurfaceControl);
+ }
+
+ @Override
+ public SurfaceControl.Builder makeAnimationLeash() {
+ return mTask.makeAnimationLeash();
+ }
+
+ @Override
+ public SurfaceControl getAnimationLeashParent() {
+ return mTask.getAnimationLeashParent();
+ }
+
+ @Override
+ public SurfaceControl getSurfaceControl() {
+ return mSurfaceControl;
+ }
+
+ @Override
+ public SurfaceControl getParentSurfaceControl() {
+ return mTask.mSurfaceAnimator.mLeash;
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return mWidth;
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return mHeight;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a6c9257..7751560 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -202,6 +202,7 @@
import android.view.IPinnedStackListener;
import android.view.IRecentsAnimationRunner;
import android.view.IRotationWatcher;
+import android.view.ISystemGestureExclusionListener;
import android.view.IWallpaperVisibilityListener;
import android.view.IWindow;
import android.view.IWindowId;
@@ -274,6 +275,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.List;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -2868,8 +2870,13 @@
}
@Override
- public boolean isKeyguardSecure() {
- int userId = UserHandle.getCallingUserId();
+ public boolean isKeyguardSecure(int userId) {
+ if (userId != UserHandle.getCallingUserId()
+ && !checkCallingPermission(Manifest.permission.INTERACT_ACROSS_USERS,
+ "isKeyguardSecure")) {
+ throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
+ }
+
long origId = Binder.clearCallingIdentity();
try {
return mPolicy.isKeyguardSecure(userId);
@@ -3812,6 +3819,42 @@
}
@Override
+ public void registerSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+ int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent == null) {
+ throw new IllegalArgumentException("Trying to register visibility event "
+ + "for invalid display: " + displayId);
+ }
+ displayContent.registerSystemGestureExclusionListener(listener);
+ }
+ }
+
+ @Override
+ public void unregisterSystemGestureExclusionListener(ISystemGestureExclusionListener listener,
+ int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent == null) {
+ throw new IllegalArgumentException("Trying to register visibility event "
+ + "for invalid display: " + displayId);
+ }
+ displayContent.unregisterSystemGestureExclusionListener(listener);
+ }
+ }
+
+ void reportSystemGestureExclusionChanged(Session session, IWindow window,
+ List<Rect> exclusionRects) {
+ synchronized (mGlobalLock) {
+ final WindowState win = windowForClientLocked(session, window, true);
+ if (win.setSystemGestureExclusion(exclusionRects)) {
+ win.getDisplayContent().updateSystemGestureExclusion();
+ }
+ }
+ }
+
+ @Override
public void registerDisplayFoldListener(IDisplayFoldListener listener) {
mPolicy.registerDisplayFoldListener(listener);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ee445d8..600178f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -205,6 +205,7 @@
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
import java.util.function.Predicate;
/** A window in the window manager. */
@@ -363,6 +364,13 @@
*/
private final Rect mInsetFrame = new Rect();
+ /**
+ * List of rects where system gestures should be ignored.
+ *
+ * Coordinates are relative to the window's position.
+ */
+ private final List<Rect> mExclusionRects = new ArrayList<>();
+
// If a window showing a wallpaper: the requested offset for the
// wallpaper; if a wallpaper window: the currently applied offset.
float mWallpaperX = -1;
@@ -612,6 +620,24 @@
}
}
+ List<Rect> getSystemGestureExclusion() {
+ return mExclusionRects;
+ }
+
+ /**
+ * Sets the system gesture exclusion rects.
+ *
+ * @return {@code true} if anything changed
+ */
+ boolean setSystemGestureExclusion(List<Rect> exclusionRects) {
+ if (mExclusionRects.equals(exclusionRects)) {
+ return false;
+ }
+ mExclusionRects.clear();
+ mExclusionRects.addAll(exclusionRects);
+ return true;
+ }
+
interface PowerManagerWrapper {
void wakeUp(long time, @WakeReason int reason, String details);
diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java
new file mode 100644
index 0000000..1458440
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java
@@ -0,0 +1,45 @@
+/*
+ * 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.wm.utils;
+
+import android.graphics.Rect;
+import android.graphics.Region;
+
+import java.util.List;
+
+/**
+ * Utility methods to handle Regions.
+ */
+public class RegionUtils {
+
+ private RegionUtils() {}
+
+
+ /**
+ * Converts a list of rects into a {@code Region}.
+ *
+ * @param rects the list of rects to convert
+ * @param outRegion the Region to set to the list of rects
+ */
+ public static void rectListToRegion(List<Rect> rects, Region outRegion) {
+ outRegion.setEmpty();
+ final int n = rects.size();
+ for (int i = 0; i < n; i++) {
+ outRegion.union(rects.get(i));
+ }
+ }
+}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 050a079..00b815a 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -109,6 +109,7 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.input.classifier@1.0",
"android.hardware.ir@1.0",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 7c236e1..a6e9fdd 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -71,6 +71,7 @@
static jmethodID method_reportNavigationMessages;
static jmethodID method_reportLocationBatch;
static jmethodID method_reportGnssServiceDied;
+static jmethodID method_setMeasurementCorrectionsCapabilities;
static jmethodID method_correctionsGetLatitudeDegrees;
static jmethodID method_correctionsGetLongitudeDegrees;
static jmethodID method_correctionsGetAltitudeMeters;
@@ -118,7 +119,6 @@
using android::hardware::gnss::V1_0::IAGnssRilCallback;
using android::hardware::gnss::V1_0::IGnssBatching;
using android::hardware::gnss::V1_0::IGnssBatchingCallback;
-using android::hardware::gnss::V1_0::IGnssDebug;
using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
using android::hardware::gnss::V1_0::IGnssGeofencing;
using android::hardware::gnss::V1_0::IGnssNavigationMessage;
@@ -142,9 +142,12 @@
using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
+using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssDebug_V1_0 = android::hardware::gnss::V1_0::IGnssDebug;
+using IGnssDebug_V2_0 = android::hardware::gnss::V2_0::IGnssDebug;
using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
@@ -158,10 +161,9 @@
using IAGnssCallback_V1_0 = android::hardware::gnss::V1_0::IAGnssCallback;
using IAGnssCallback_V2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
-using IMeasurementCorrections =
- android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
-using GnssSingleSatCorrectionFlags =
- android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback;
@@ -191,7 +193,8 @@
sp<IAGnss_V1_0> agnssIface = nullptr;
sp<IAGnss_V2_0> agnssIface_V2_0 = nullptr;
sp<IGnssBatching> gnssBatchingIface = nullptr;
-sp<IGnssDebug> gnssDebugIface = nullptr;
+sp<IGnssDebug_V1_0> gnssDebugIface = nullptr;
+sp<IGnssDebug_V2_0> gnssDebugIface_V2_0 = nullptr;
sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr;
@@ -201,7 +204,6 @@
sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr;
sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr;
-
sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
#define WAKE_LOCK_NAME "GPS"
@@ -336,7 +338,7 @@
template<>
const char *const JavaMethodHelper<bool>::signature_ = "(Z)V";
template<>
-const char *const JavaMethodHelper<jstring>::signature_ = "(Ljava/lang/String)V";
+const char *const JavaMethodHelper<jstring>::signature_ = "(Ljava/lang/String;)V";
#define SET(setter, value) object.callSetter("set" # setter, (value))
@@ -549,7 +551,9 @@
struct GnssCallback : public IGnssCallback {
Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
- Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
+ Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
+ return gnssSvStatusCbImpl(svStatus);
+ }
Return<void> gnssNmeaCb(int64_t timestamp, const android::hardware::hidl_string& nmea) override;
Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
Return<void> gnssAcquireWakelockCb() override;
@@ -567,14 +571,47 @@
override;
Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
+ Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) override {
+ return gnssSvStatusCbImpl(svInfoList);
+ }
- // Templated implementation for gnnsLocationCb and gnnsLocationCb_2_0.
- template <class T>
- Return<void> gnssLocationCbImpl(const T& location);
+ Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags);
- // TODO(b/73306084): Reconsider allocation cost vs threadsafety on these statics
+ // TODO: Reconsider allocation cost vs threadsafety on these statics
static const char* sNmeaString;
static size_t sNmeaStringLength;
+private:
+ template<class T>
+ Return<void> gnssLocationCbImpl(const T& location);
+
+ template<class T>
+ Return<void> gnssSvStatusCbImpl(const T& svStatus);
+
+ uint32_t getGnssSvInfoListSize(const IGnssCallback_V1_0::GnssSvStatus& svStatus) {
+ return svStatus.numSvs;
+ }
+
+ uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) {
+ return svInfoList.size();
+ }
+
+ const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+ const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
+ return svStatus.gnssSvList.data()[i];
+ }
+
+ const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+ return svInfoList[i].v1_0;
+ }
+
+ uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
+ return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
+ }
+
+ uint32_t getConstellationType(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].constellation);
+ }
};
Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
@@ -622,10 +659,11 @@
return Void();
}
-Return<void> GnssCallback::gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) {
+template<class T>
+Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
JNIEnv* env = getJniEnv();
- uint32_t listSize = svStatus.numSvs;
+ uint32_t listSize = getGnssSvInfoListSize(svStatus);
if (listSize > static_cast<uint32_t>(
android::hardware::gnss::V1_0::GnssMax::SVS_COUNT)) {
ALOGD("Too many satellites %u. Clamps to %u.", listSize,
@@ -654,9 +692,9 @@
CONSTELLATION_TYPE_SHIFT_WIDTH = 4
};
- const IGnssCallback::GnssSvInfo& info = svStatus.gnssSvList.data()[i];
+ const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i);
svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
- (static_cast<uint32_t>(info.constellation) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
+ (getConstellationType(svStatus, i) << CONSTELLATION_TYPE_SHIFT_WIDTH) |
static_cast<uint32_t>(info.svFlag);
cn0s[i] = info.cN0Dbhz;
elev[i] = info.elevationDegrees;
@@ -694,16 +732,29 @@
}
Return<void> GnssCallback::gnssSetCapabilitesCb(uint32_t capabilities) {
- ALOGD("%s: %du\n", __func__, capabilities);
-
- JNIEnv* env = getJniEnv();
- env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
- return Void();
+ return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+ /* hasSubHalCapabilityFlags = */ true);
}
Return<void> GnssCallback::gnssSetCapabilitiesCb_2_0(uint32_t capabilities) {
- return GnssCallback::gnssSetCapabilitesCb(capabilities);
+ return GnssCallback::gnssSetCapabilitesCbImpl(capabilities,
+ /* hasSubHalCapabilityFlags = */ false);
+}
+
+Return <void> GnssCallback::gnssSetCapabilitesCbImpl(uint32_t capabilities,
+ bool hasSubHalCapabilityFlags) {
+ // The IGnssCallback.hal@2.0 removed sub-HAL capability flags from the Capabilities enum
+ // and instead uses the sub-HAL non-null handle returned from IGnss.hal@2.0 to indicate
+ // support. Therefore, the 'hasSubHalCapabilityFlags' parameter is needed to tell if the
+ // 'capabilities' parameter includes the sub-HAL capability flags or not. Old HALs
+ // which explicitly set the sub-HAL capability bits must continue to work.
+ ALOGD("%s: capabilities=%du, hasSubHalCapabilityFlags=%d\n", __func__, capabilities,
+ hasSubHalCapabilityFlags);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities,
+ boolToJbool(hasSubHalCapabilityFlags));
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
}
Return<void> GnssCallback::gnssAcquireWakelockCb() {
@@ -1065,6 +1116,9 @@
// Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated.
SET(State, static_cast<int32_t>(measurement_V2_0->state));
+
+ // Overwrite with v2_0.constellation since v2_0->v1_1->v1_0.constellation is deprecated.
+ SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation));
}
jobject GnssMeasurementCallback::translateGnssClock(
@@ -1153,6 +1207,22 @@
}
/*
+ * MeasurementCorrectionsCallback implements callback methods of interface
+ * IMeasurementCorrectionsCallback.hal.
+ */
+struct MeasurementCorrectionsCallback : public IMeasurementCorrectionsCallback {
+ Return<void> setCapabilitiesCb(uint32_t capabilities) override;
+};
+
+Return<void> MeasurementCorrectionsCallback::setCapabilitiesCb(uint32_t capabilities) {
+ ALOGD("%s: %du\n", __func__, capabilities);
+ JNIEnv* env = getJniEnv();
+ env->CallVoidMethod(mCallbacksObj, method_setMeasurementCorrectionsCapabilities, capabilities);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ return Void();
+}
+
+/*
* GnssNiCallback implements callback methods required by the IGnssNi interface.
*/
struct GnssNiCallback : public IGnssNiCallback {
@@ -1434,7 +1504,7 @@
method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
- method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
+ method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(IZ)V");
method_setGnssYearOfHardware = env->GetMethodID(clazz, "setGnssYearOfHardware", "(I)V");
method_setGnssHardwareModelName = env->GetMethodID(clazz, "setGnssHardwareModelName",
"(Ljava/lang/String;)V");
@@ -1474,6 +1544,9 @@
"(Ljava/lang/String;BLjava/lang/String;BLjava/lang/String;BZZ)V");
method_isInEmergencySession = env->GetMethodID(clazz, "isInEmergencySession", "()Z");
+ method_setMeasurementCorrectionsCapabilities = env->GetMethodID(clazz,
+ "setMeasurementCorrectionsCapabilities", "(I)V");
+
jclass measCorrClass = env->FindClass("android/location/GnssMeasurementCorrections");
method_correctionsGetLatitudeDegrees = env->GetMethodID(
measCorrClass,"getLatitudeDegrees", "()D");
@@ -1591,7 +1664,7 @@
}
if (gnssHal_V2_0 != nullptr) {
- // TODO(b/119638366): getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
+ // TODO: getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
if (!gnssMeasurement.isOk()) {
ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
@@ -1623,11 +1696,21 @@
}
}
- auto gnssDebug = gnssHal->getExtensionGnssDebug();
- if (!gnssDebug.isOk()) {
- ALOGD("Unable to get a handle to GnssDebug");
+ if (gnssHal_V2_0 != nullptr) {
+ auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0();
+ if (!gnssDebug.isOk()) {
+ ALOGD("Unable to get a handle to GnssDebug_V2_0");
+ } else {
+ gnssDebugIface_V2_0 = gnssDebug;
+ gnssDebugIface = gnssDebugIface_V2_0;
+ }
} else {
- gnssDebugIface = gnssDebug;
+ auto gnssDebug = gnssHal->getExtensionGnssDebug();
+ if (!gnssDebug.isOk()) {
+ ALOGD("Unable to get a handle to GnssDebug");
+ } else {
+ gnssDebugIface = gnssDebug;
+ }
}
auto gnssNi = gnssHal->getExtensionGnssNi();
@@ -1795,6 +1878,12 @@
gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
}
+ if (gnssCorrectionsIface != nullptr) {
+ sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
+ new MeasurementCorrectionsCallback();
+ gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
+ }
+
return JNI_TRUE;
}
@@ -2150,76 +2239,100 @@
gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response));
}
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
+ return satelliteDataArray[i];
+}
+
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
+ return satelliteDataArray[i].v1_0;
+}
+
+template<class T>
+uint32_t getConstellationType(const hidl_vec<T>& satelliteDataArray, size_t i) {
+ return static_cast<uint32_t>(satelliteDataArray[i].constellation);
+}
+
+template<class T>
+static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, const T& data) {
+ internalState << "Gnss Location Data:: ";
+ if (!data.position.valid) {
+ internalState << "not valid";
+ } else {
+ internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
+ << ", LongitudeDegrees: " << data.position.longitudeDegrees
+ << ", altitudeMeters: " << data.position.altitudeMeters
+ << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
+ << ", bearingDegrees: " << data.position.bearingDegrees
+ << ", horizontalAccuracyMeters: "
+ << data.position.horizontalAccuracyMeters
+ << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
+ << ", speedAccuracyMetersPerSecond: "
+ << data.position.speedAccuracyMetersPerSecond
+ << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
+ << ", ageSeconds: " << data.position.ageSeconds;
+ }
+ internalState << std::endl;
+
+ internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
+ << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
+ << ", frequencyUncertaintyNsPerSec: "
+ << data.time.frequencyUncertaintyNsPerSec << std::endl;
+
+ if (data.satelliteDataArray.size() != 0) {
+ internalState << "Satellite Data for " << data.satelliteDataArray.size()
+ << " satellites:: " << std::endl;
+ }
+
+ internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL, 7=IRNSS; "
+ << "ephType: 0=Eph, 1=Alm, 2=Unk; "
+ << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
+ << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
+ for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
+ IGnssDebug_V1_0::SatelliteData satelliteData =
+ getSatelliteData(data.satelliteDataArray, i);
+ internalState << "constell: "
+ << getConstellationType(data.satelliteDataArray, i)
+ << ", svid: " << std::setw(3) << satelliteData.svid
+ << ", serverPredAvail: "
+ << satelliteData.serverPredictionIsAvailable
+ << ", serverPredAgeSec: " << std::setw(7)
+ << satelliteData.serverPredictionAgeSeconds
+ << ", ephType: "
+ << static_cast<uint32_t>(satelliteData.ephemerisType)
+ << ", ephSource: "
+ << static_cast<uint32_t>(satelliteData.ephemerisSource)
+ << ", ephHealth: "
+ << static_cast<uint32_t>(satelliteData.ephemerisHealth)
+ << ", ephAgeSec: " << std::setw(7)
+ << satelliteData.ephemerisAgeSeconds << std::endl;
+ }
+ return (jstring) env->NewStringUTF(internalState.str().c_str());
+}
+
static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
jobject /* obj */) {
jstring result = nullptr;
/*
- * TODO(b/33089503) : Create a jobject to represent GnssDebug.
+ * TODO: Create a jobject to represent GnssDebug.
*/
std::stringstream internalState;
if (gnssDebugIface == nullptr) {
internalState << "Gnss Debug Interface not available" << std::endl;
- } else {
- IGnssDebug::DebugData data;
- gnssDebugIface->getDebugData([&data](const IGnssDebug::DebugData& debugData) {
+ } else if (gnssDebugIface_V2_0 != nullptr) {
+ IGnssDebug_V2_0::DebugData data;
+ gnssDebugIface_V2_0->getDebugData_2_0([&data](const IGnssDebug_V2_0::DebugData& debugData) {
data = debugData;
});
-
- internalState << "Gnss Location Data:: ";
- if (!data.position.valid) {
- internalState << "not valid";
- } else {
- internalState << "LatitudeDegrees: " << data.position.latitudeDegrees
- << ", LongitudeDegrees: " << data.position.longitudeDegrees
- << ", altitudeMeters: " << data.position.altitudeMeters
- << ", speedMetersPerSecond: " << data.position.speedMetersPerSec
- << ", bearingDegrees: " << data.position.bearingDegrees
- << ", horizontalAccuracyMeters: "
- << data.position.horizontalAccuracyMeters
- << ", verticalAccuracyMeters: " << data.position.verticalAccuracyMeters
- << ", speedAccuracyMetersPerSecond: "
- << data.position.speedAccuracyMetersPerSecond
- << ", bearingAccuracyDegrees: " << data.position.bearingAccuracyDegrees
- << ", ageSeconds: " << data.position.ageSeconds;
- }
- internalState << std::endl;
-
- internalState << "Gnss Time Data:: timeEstimate: " << data.time.timeEstimate
- << ", timeUncertaintyNs: " << data.time.timeUncertaintyNs
- << ", frequencyUncertaintyNsPerSec: "
- << data.time.frequencyUncertaintyNsPerSec << std::endl;
-
- if (data.satelliteDataArray.size() != 0) {
- internalState << "Satellite Data for " << data.satelliteDataArray.size()
- << " satellites:: " << std::endl;
- }
-
- internalState << "constell: 1=GPS, 2=SBAS, 3=GLO, 4=QZSS, 5=BDS, 6=GAL; "
- << "ephType: 0=Eph, 1=Alm, 2=Unk; "
- << "ephSource: 0=Demod, 1=Supl, 2=Server, 3=Unk; "
- << "ephHealth: 0=Good, 1=Bad, 2=Unk" << std::endl;
- for (size_t i = 0; i < data.satelliteDataArray.size(); i++) {
- internalState << "constell: "
- << static_cast<uint32_t>(data.satelliteDataArray[i].constellation)
- << ", svid: " << std::setw(3) << data.satelliteDataArray[i].svid
- << ", serverPredAvail: "
- << data.satelliteDataArray[i].serverPredictionIsAvailable
- << ", serverPredAgeSec: " << std::setw(7)
- << data.satelliteDataArray[i].serverPredictionAgeSeconds
- << ", ephType: "
- << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisType)
- << ", ephSource: "
- << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisSource)
- << ", ephHealth: "
- << static_cast<uint32_t>(data.satelliteDataArray[i].ephemerisHealth)
- << ", ephAgeSec: " << std::setw(7)
- << data.satelliteDataArray[i].ephemerisAgeSeconds << std::endl;
- }
+ result = parseDebugData(env, internalState, data);
+ } else {
+ IGnssDebug_V1_0::DebugData data;
+ gnssDebugIface->getDebugData([&data](const IGnssDebug_V1_0::DebugData& debugData) {
+ data = debugData;
+ });
+ result = parseDebugData(env, internalState, data);
}
-
- result = env->NewStringUTF(internalState.str().c_str());
return result;
}
@@ -2380,13 +2493,25 @@
return boolToJbool(result.isOk());
}
-static jboolean android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections(
+static jboolean
+ android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported(
+ JNIEnv* env, jclass clazz) {
+ if (gnssCorrectionsIface != nullptr) {
+ return JNI_TRUE;
+ }
+
+ return JNI_FALSE;
+}
+
+static jboolean
+ android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections(
JNIEnv* env,
jobject obj /* clazz*/,
jobject correctionsObj) {
if (gnssCorrectionsIface == nullptr) {
- ALOGW("Trying to inject GNSS corrections on a chipset that does not support them.");
+ ALOGW("Trying to inject GNSS measurement corrections on a chipset that does not"
+ " support them.");
return JNI_FALSE;
}
@@ -2882,18 +3007,25 @@
static const JNINativeMethod sMeasurementMethods[] = {
/* name, signature, funcPtr */
{"native_is_measurement_supported", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_is_measurement_supported)},
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementsProvider_is_measurement_supported)},
{"native_start_measurement_collection", "(Z)Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_start_measurement_collection)},
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementsProvider_start_measurement_collection)},
{"native_stop_measurement_collection", "()Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementsProvider_stop_measurement_collection)},
+};
+
+static const JNINativeMethod sMeasurementCorrectionsMethods[] = {
+ /* name, signature, funcPtr */
+ {"native_is_measurement_corrections_supported", "()Z",
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementCorrectionsProvider_is_measurement_corrections_supported)},
{"native_inject_gnss_measurement_corrections",
- "(Landroid/location/GnssMeasurementCorrections;)Z",
- reinterpret_cast<void*>(
- android_location_GnssMeasurementsProvider_inject_gnss_measurement_corrections)},
+ "(Landroid/location/GnssMeasurementCorrections;)Z",
+ reinterpret_cast<void*>(
+ android_location_GnssMeasurementCorrectionsProvider_inject_gnss_measurement_corrections)},
};
static const JNINativeMethod sNavigationMessageMethods[] = {
@@ -2992,6 +3124,11 @@
NELEM(sMeasurementMethods));
jniRegisterNativeMethods(
env,
+ "com/android/server/location/GnssMeasurementCorrectionsProvider",
+ sMeasurementCorrectionsMethods,
+ NELEM(sMeasurementCorrectionsMethods));
+ jniRegisterNativeMethods(
+ env,
"com/android/server/location/GnssNavigationMessageProvider",
sNavigationMessageMethods,
NELEM(sNavigationMessageMethods));
diff --git a/services/ipmemorystore/Android.bp b/services/ipmemorystore/Android.bp
deleted file mode 100644
index 013cf56..0000000
--- a/services/ipmemorystore/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-java_library_static {
- name: "services.ipmemorystore",
- srcs: ["java/**/*.java"],
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3f323d9..419f52c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -108,7 +108,6 @@
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
-import com.android.server.net.ipmemorystore.IpMemoryStoreService;
import com.android.server.net.watchlist.NetworkWatchlistService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.oemlock.OemLockService;
@@ -1231,6 +1230,7 @@
}
startContentCaptureService(context);
+ startAttentionService(context);
// App prediction manager service
traceBeginAndSlog("StartAppPredictionService");
@@ -1264,14 +1264,6 @@
}
traceEnd();
- traceBeginAndSlog("StartIpMemoryStoreService");
- try {
- ServiceManager.addService(Context.IP_MEMORY_STORE_SERVICE,
- new IpMemoryStoreService(context));
- } catch (Throwable e) {
- reportWtf("starting IP Memory Store Service", e);
- }
- traceEnd();
traceBeginAndSlog("StartIpSecService");
try {
@@ -1293,10 +1285,6 @@
traceEnd();
}
- traceBeginAndSlog("StartAttentionManagerService");
- mSystemServiceManager.startService(AttentionManagerService.class);
- traceEnd();
-
traceBeginAndSlog("StartNetworkScoreService");
mSystemServiceManager.startService(NetworkScoreService.Lifecycle.class);
traceEnd();
@@ -2269,6 +2257,17 @@
traceEnd();
}
+ private void startAttentionService(@NonNull Context context) {
+ if (!AttentionManagerService.isServiceConfigured(context)) {
+ Slog.d(TAG, "AttentionService is not configured on this device");
+ return;
+ }
+
+ traceBeginAndSlog("StartAttentionManagerService");
+ mSystemServiceManager.startService(AttentionManagerService.class);
+ traceEnd();
+ }
+
static final void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 8ad4d76..486d15d 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -7,6 +7,19 @@
]
}
+java_library_static {
+ name: "ipmemorystore-client",
+ sdk_version: "system_current",
+ srcs: [
+ ":framework-annotations",
+ "java/android/net/IpMemoryStoreClient.java",
+ "java/android/net/ipmemorystore/**.java",
+ ],
+ static_libs: [
+ "ipmemorystore-aidl-interfaces-java",
+ ]
+}
+
filegroup {
name: "services-networkstack-shared-srcs",
srcs: [
diff --git a/services/net/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStore.java
new file mode 100644
index 0000000..9248299
--- /dev/null
+++ b/services/net/java/android/net/IpMemoryStore.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.net;
+
+import android.annotation.NonNull;
+import android.content.Context;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * Manager class used to communicate with the ip memory store service in the network stack,
+ * which is running in a separate module.
+ * @hide
+*/
+public class IpMemoryStore extends IpMemoryStoreClient {
+ private final CompletableFuture<IIpMemoryStore> mService;
+
+ public IpMemoryStore(@NonNull final Context context) {
+ super(context);
+ mService = new CompletableFuture<>();
+ getNetworkStackClient().fetchIpMemoryStore(
+ new IIpMemoryStoreCallbacks.Stub() {
+ @Override
+ public void onIpMemoryStoreFetched(final IIpMemoryStore memoryStore) {
+ mService.complete(memoryStore);
+ }
+ });
+ }
+
+ @Override
+ protected IIpMemoryStore getService() throws InterruptedException, ExecutionException {
+ return mService.get();
+ }
+
+ @VisibleForTesting
+ protected NetworkStackClient getNetworkStackClient() {
+ return NetworkStackClient.getInstance();
+ }
+
+ /** Gets an instance of the memory store */
+ @NonNull
+ public static IpMemoryStore getMemoryStore(final Context context) {
+ return new IpMemoryStore(context);
+ }
+}
diff --git a/core/java/android/net/IpMemoryStore.java b/services/net/java/android/net/IpMemoryStoreClient.java
similarity index 68%
rename from core/java/android/net/IpMemoryStore.java
rename to services/net/java/android/net/IpMemoryStoreClient.java
index 2f4d9bc..2f4fdbd 100644
--- a/core/java/android/net/IpMemoryStore.java
+++ b/services/net/java/android/net/IpMemoryStoreClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemService;
import android.content.Context;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -27,23 +26,34 @@
import android.net.ipmemorystore.IOnSameNetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
import android.os.RemoteException;
+import android.util.Log;
-import com.android.internal.util.Preconditions;
+import java.util.concurrent.ExecutionException;
/**
- * The interface for system components to access the IP memory store.
- * @see com.android.server.net.ipmemorystore.IpMemoryStoreService
+ * service used to communicate with the ip memory store service in network stack,
+ * which is running in a separate module.
* @hide
*/
-@SystemService(Context.IP_MEMORY_STORE_SERVICE)
-public class IpMemoryStore {
- @NonNull final Context mContext;
- @NonNull final IIpMemoryStore mService;
+public abstract class IpMemoryStoreClient {
+ private static final String TAG = IpMemoryStoreClient.class.getSimpleName();
+ private final Context mContext;
- public IpMemoryStore(@NonNull final Context context, @NonNull final IIpMemoryStore service) {
- mContext = Preconditions.checkNotNull(context, "missing context");
- mService = Preconditions.checkNotNull(service, "missing IIpMemoryStore");
+ public IpMemoryStoreClient(@NonNull final Context context) {
+ if (context == null) throw new IllegalArgumentException("missing context");
+ mContext = context;
+ }
+
+ @NonNull
+ protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException;
+
+ protected StatusParcelable internalErrorStatus() {
+ final StatusParcelable error = new StatusParcelable();
+ error.resultCode = Status.ERROR_UNKNOWN;
+ return error;
}
/**
@@ -66,9 +76,13 @@
@NonNull final NetworkAttributes attributes,
@Nullable final IOnStatusListener listener) {
try {
- mService.storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+ try {
+ getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onComplete(internalErrorStatus());
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error storing network attributes", e);
}
}
@@ -87,9 +101,13 @@
@NonNull final String name, @NonNull final Blob data,
@Nullable final IOnStatusListener listener) {
try {
- mService.storeBlob(l2Key, clientId, name, data, listener);
+ try {
+ getService().storeBlob(l2Key, clientId, name, data, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onComplete(internalErrorStatus());
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error storing blob", e);
}
}
@@ -110,9 +128,13 @@
public void findL2Key(@NonNull final NetworkAttributes attributes,
@NonNull final IOnL2KeyResponseListener listener) {
try {
- mService.findL2Key(attributes.toParcelable(), listener);
+ try {
+ getService().findL2Key(attributes.toParcelable(), listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onL2KeyResponse(internalErrorStatus(), null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error finding L2 Key", e);
}
}
@@ -128,9 +150,13 @@
public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
@NonNull final IOnSameNetworkResponseListener listener) {
try {
- mService.isSameNetwork(l2Key1, l2Key2, listener);
+ try {
+ getService().isSameNetwork(l2Key1, l2Key2, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onSameNetworkResponse(internalErrorStatus(), null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error checking for network sameness", e);
}
}
@@ -146,9 +172,13 @@
public void retrieveNetworkAttributes(@NonNull final String l2Key,
@NonNull final IOnNetworkAttributesRetrieved listener) {
try {
- mService.retrieveNetworkAttributes(l2Key, listener);
+ try {
+ getService().retrieveNetworkAttributes(l2Key, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error retrieving network attributes", e);
}
}
@@ -166,14 +196,13 @@
public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
@NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
try {
- mService.retrieveBlob(l2Key, clientId, name, listener);
+ try {
+ getService().retrieveBlob(l2Key, clientId, name, listener);
+ } catch (InterruptedException | ExecutionException m) {
+ listener.onBlobRetrieved(internalErrorStatus(), null, null, null);
+ }
} catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ Log.e(TAG, "Error retrieving blob", e);
}
}
-
- /** Gets an instance of the memory store */
- public static IpMemoryStore getMemoryStore(final Context context) {
- return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE);
- }
}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index fe447fc..7befd087 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -120,8 +120,7 @@
*
* <p>The INetworkMonitor will be returned asynchronously through the provided callbacks.
*/
- public void makeNetworkMonitor(
- NetworkParcelable network, String name, INetworkMonitorCallbacks cb) {
+ public void makeNetworkMonitor(Network network, String name, INetworkMonitorCallbacks cb) {
requestConnector(connector -> {
try {
connector.makeNetworkMonitor(network, name, cb);
@@ -131,6 +130,21 @@
});
}
+ /**
+ * Get an instance of the IpMemoryStore.
+ *
+ * <p>The IpMemoryStore will be returned asynchronously through the provided callbacks.
+ */
+ public void fetchIpMemoryStore(IIpMemoryStoreCallbacks cb) {
+ requestConnector(connector -> {
+ try {
+ connector.fetchIpMemoryStore(cb);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ });
+ }
+
private class NetworkStackConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
similarity index 78%
rename from core/java/android/net/TcpKeepalivePacketData.java
rename to services/net/java/android/net/TcpKeepalivePacketData.java
index 99d36c5..d79ad1f 100644
--- a/core/java/android/net/TcpKeepalivePacketData.java
+++ b/services/net/java/android/net/TcpKeepalivePacketData.java
@@ -25,8 +25,8 @@
import android.os.Parcelable;
import android.system.OsConstants;
-import java.net.Inet4Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Objects;
@@ -56,10 +56,10 @@
// This should only be constructed via static factory methods, such as
// tcpKeepalivePacket.
- private TcpKeepalivePacketData(TcpSocketInfo tcpDetails, byte[] data)
- throws InvalidPacketException {
- super(tcpDetails.srcAddress, tcpDetails.srcPort, tcpDetails.dstAddress,
- tcpDetails.dstPort, data);
+ private TcpKeepalivePacketData(final TcpKeepalivePacketDataParcelable tcpDetails,
+ final byte[] data) throws InvalidPacketException, UnknownHostException {
+ super(InetAddress.getByAddress(tcpDetails.srcAddress), tcpDetails.srcPort,
+ InetAddress.getByAddress(tcpDetails.dstAddress), tcpDetails.dstPort, data);
tcpSeq = tcpDetails.seq;
tcpAck = tcpDetails.ack;
// In the packet, the window is shifted right by the window scale.
@@ -71,17 +71,22 @@
* Factory method to create tcp keepalive packet structure.
*/
public static TcpKeepalivePacketData tcpKeepalivePacket(
- TcpSocketInfo tcpDetails) throws InvalidPacketException {
+ TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException {
final byte[] packet;
- if ((tcpDetails.srcAddress instanceof Inet4Address)
- && (tcpDetails.dstAddress instanceof Inet4Address)) {
- packet = buildV4Packet(tcpDetails);
- } else {
- // TODO: support ipv6
+ try {
+ if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null)
+ && (tcpDetails.srcAddress.length == 4 /* V4 IP length */)
+ && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) {
+ packet = buildV4Packet(tcpDetails);
+ } else {
+ // TODO: support ipv6
+ throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+ }
+ return new TcpKeepalivePacketData(tcpDetails, packet);
+ } catch (UnknownHostException e) {
throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
}
- return new TcpKeepalivePacketData(tcpDetails, packet);
}
/**
@@ -89,7 +94,7 @@
*/
// TODO : if this code is ever moved to the network stack, factorize constants with the ones
// over there.
- private static byte[] buildV4Packet(TcpSocketInfo tcpDetails) {
+ private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) {
final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.BIG_ENDIAN);
@@ -102,8 +107,8 @@
buf.put((byte) OsConstants.IPPROTO_TCP);
final int ipChecksumOffset = buf.position();
buf.putShort((short) 0); // IP checksum
- buf.put(tcpDetails.srcAddress.getAddress());
- buf.put(tcpDetails.dstAddress.getAddress());
+ buf.put(tcpDetails.srcAddress);
+ buf.put(tcpDetails.dstAddress);
buf.putShort((short) tcpDetails.srcPort);
buf.putShort((short) tcpDetails.dstPort);
buf.putInt(tcpDetails.seq); // Sequence Number
@@ -122,31 +127,6 @@
// TODO: add buildV6Packet.
- /** Represents tcp/ip information. */
- // TODO: Replace TcpSocketInfo with TcpKeepalivePacketDataParcelable.
- public static class TcpSocketInfo {
- public final InetAddress srcAddress;
- public final InetAddress dstAddress;
- public final int srcPort;
- public final int dstPort;
- public final int seq;
- public final int ack;
- public final int rcvWnd;
- public final int rcvWndScale;
-
- public TcpSocketInfo(InetAddress sAddr, int sPort, InetAddress dAddr,
- int dPort, int writeSeq, int readSeq, int rWnd, int rWndScale) {
- srcAddress = sAddr;
- dstAddress = dAddr;
- srcPort = sPort;
- dstPort = dPort;
- seq = writeSeq;
- ack = readSeq;
- rcvWnd = rWnd;
- rcvWndScale = rWndScale;
- }
- }
-
@Override
public boolean equals(@Nullable final Object o) {
if (!(o instanceof TcpKeepalivePacketData)) return false;
@@ -167,8 +147,9 @@
tcpWndScale);
}
- /* Parcelable Implementation. */
- /* Note that this object implements parcelable (and needs to keep doing this as it inherits
+ /**
+ * Parcelable Implementation.
+ * Note that this object implements parcelable (and needs to keep doing this as it inherits
* from a class that does), but should usually be parceled as a stable parcelable using
* the toStableParcelable() and fromStableParcelable() methods.
*/
@@ -194,7 +175,7 @@
}
/** Parcelable Creator. */
- public static final @android.annotation.NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+ public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
new Parcelable.Creator<TcpKeepalivePacketData>() {
public TcpKeepalivePacketData createFromParcel(Parcel in) {
return new TcpKeepalivePacketData(in);
@@ -217,6 +198,8 @@
parcel.dstPort = dstPort;
parcel.seq = tcpSeq;
parcel.ack = tcpAck;
+ parcel.rcvWnd = tcpWnd;
+ parcel.rcvWndScale = tcpWndScale;
return parcel;
}
diff --git a/services/net/java/android/net/ip/IpClientUtil.java b/services/net/java/android/net/ip/IpClientUtil.java
index bf917bf..90624e0 100644
--- a/services/net/java/android/net/ip/IpClientUtil.java
+++ b/services/net/java/android/net/ip/IpClientUtil.java
@@ -17,12 +17,10 @@
package android.net.ip;
import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable;
-import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
import android.content.Context;
import android.net.DhcpResultsParcelable;
import android.net.LinkProperties;
-import android.net.LinkPropertiesParcelable;
import android.net.NetworkStackClient;
import android.os.ConditionVariable;
@@ -122,18 +120,18 @@
}
@Override
- public void onProvisioningSuccess(LinkPropertiesParcelable newLp) {
- mCb.onProvisioningSuccess(fromStableParcelable(newLp));
+ public void onProvisioningSuccess(LinkProperties newLp) {
+ mCb.onProvisioningSuccess(newLp);
}
@Override
- public void onProvisioningFailure(LinkPropertiesParcelable newLp) {
- mCb.onProvisioningFailure(fromStableParcelable(newLp));
+ public void onProvisioningFailure(LinkProperties newLp) {
+ mCb.onProvisioningFailure(newLp);
}
// Invoked on LinkProperties changes.
@Override
- public void onLinkPropertiesChange(LinkPropertiesParcelable newLp) {
- mCb.onLinkPropertiesChange(fromStableParcelable(newLp));
+ public void onLinkPropertiesChange(LinkProperties newLp) {
+ mCb.onLinkPropertiesChange(newLp);
}
// Called when the internal IpReachabilityMonitor (if enabled) has
diff --git a/core/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/NetworkAttributes.java
rename to services/net/java/android/net/ipmemorystore/NetworkAttributes.java
diff --git a/core/java/android/net/ipmemorystore/SameL3NetworkResponse.java b/services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
similarity index 100%
rename from core/java/android/net/ipmemorystore/SameL3NetworkResponse.java
rename to services/net/java/android/net/ipmemorystore/SameL3NetworkResponse.java
diff --git a/core/java/android/net/ipmemorystore/Status.java b/services/net/java/android/net/ipmemorystore/Status.java
similarity index 97%
rename from core/java/android/net/ipmemorystore/Status.java
rename to services/net/java/android/net/ipmemorystore/Status.java
index cacd42d..13242c0 100644
--- a/core/java/android/net/ipmemorystore/Status.java
+++ b/services/net/java/android/net/ipmemorystore/Status.java
@@ -32,6 +32,7 @@
public static final int ERROR_ILLEGAL_ARGUMENT = -2;
public static final int ERROR_DATABASE_CANNOT_BE_OPENED = -3;
public static final int ERROR_STORAGE = -4;
+ public static final int ERROR_UNKNOWN = -5;
public final int resultCode;
diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java
index 4ad7138..e423d62 100644
--- a/services/net/java/android/net/shared/InitialConfiguration.java
+++ b/services/net/java/android/net/shared/InitialConfiguration.java
@@ -23,13 +23,12 @@
import android.net.InetAddresses;
import android.net.InitialConfigurationParcelable;
import android.net.IpPrefix;
-import android.net.IpPrefixParcelable;
import android.net.LinkAddress;
-import android.net.LinkAddressParcelable;
import android.net.RouteInfo;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -148,10 +147,8 @@
*/
public InitialConfigurationParcelable toStableParcelable() {
final InitialConfigurationParcelable p = new InitialConfigurationParcelable();
- p.ipAddresses = toParcelableArray(ipAddresses,
- LinkPropertiesParcelableUtil::toStableParcelable, LinkAddressParcelable.class);
- p.directlyConnectedRoutes = toParcelableArray(directlyConnectedRoutes,
- LinkPropertiesParcelableUtil::toStableParcelable, IpPrefixParcelable.class);
+ p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]);
+ p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]);
p.dnsServers = toParcelableArray(
dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class);
return p;
@@ -164,10 +161,8 @@
public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) {
if (p == null) return null;
final InitialConfiguration config = new InitialConfiguration();
- config.ipAddresses.addAll(fromParcelableArray(
- p.ipAddresses, LinkPropertiesParcelableUtil::fromStableParcelable));
- config.directlyConnectedRoutes.addAll(fromParcelableArray(
- p.directlyConnectedRoutes, LinkPropertiesParcelableUtil::fromStableParcelable));
+ config.ipAddresses.addAll(Arrays.asList(p.ipAddresses));
+ config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes));
config.dnsServers.addAll(
fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress));
return config;
diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
index 1f0525e..6b5826f 100644
--- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
+++ b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
@@ -44,7 +44,7 @@
@Nullable StaticIpConfiguration config) {
if (config == null) return null;
final StaticIpConfigurationParcelable p = new StaticIpConfigurationParcelable();
- p.ipAddress = LinkPropertiesParcelableUtil.toStableParcelable(config.getIpAddress());
+ p.ipAddress = config.getIpAddress();
p.gateway = parcelAddress(config.getGateway());
p.dnsServers = toParcelableArray(
config.getDnsServers(), IpConfigurationParcelableUtil::parcelAddress, String.class);
@@ -59,7 +59,7 @@
@Nullable StaticIpConfigurationParcelable p) {
if (p == null) return null;
final StaticIpConfiguration config = new StaticIpConfiguration();
- config.setIpAddress(LinkPropertiesParcelableUtil.fromStableParcelable(p.ipAddress));
+ config.setIpAddress(p.ipAddress);
config.setGateway(unparcelAddress(p.gateway));
for (InetAddress addr : fromParcelableArray(
p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress)) {
diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
index 51d955d..1729da6 100644
--- a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
+++ b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java
@@ -16,25 +16,9 @@
package android.net.shared;
-import static android.net.shared.IpConfigurationParcelableUtil.parcelAddress;
-import static android.net.shared.IpConfigurationParcelableUtil.unparcelAddress;
-import static android.net.shared.ParcelableUtil.fromParcelableArray;
-import static android.net.shared.ParcelableUtil.toParcelableArray;
-
import android.annotation.Nullable;
-import android.net.IpPrefix;
-import android.net.IpPrefixParcelable;
-import android.net.LinkAddress;
-import android.net.LinkAddressParcelable;
import android.net.LinkProperties;
-import android.net.LinkPropertiesParcelable;
import android.net.ProxyInfo;
-import android.net.ProxyInfoParcelable;
-import android.net.RouteInfo;
-import android.net.RouteInfoParcelable;
-import android.net.Uri;
-
-import java.util.Arrays;
/**
* Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties
@@ -42,177 +26,22 @@
* @hide
*/
public final class LinkPropertiesParcelableUtil {
+ // Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable
+ // TODO: remove the following methods after migrating clients.
/**
- * Convert a ProxyInfo to a ProxyInfoParcelable
+ * @deprecated conversion to stable parcelable is no longer necessary.
*/
- public static ProxyInfoParcelable toStableParcelable(@Nullable ProxyInfo proxyInfo) {
- if (proxyInfo == null) {
- return null;
- }
- final ProxyInfoParcelable parcel = new ProxyInfoParcelable();
- parcel.host = proxyInfo.getHost();
- parcel.port = proxyInfo.getPort();
- parcel.exclusionList = proxyInfo.getExclusionList();
- parcel.pacFileUrl = proxyInfo.getPacFileUrl().toString();
- return parcel;
- }
-
- /**
- * Convert a ProxyInfoParcelable to a ProxyInfo
- */
- public static ProxyInfo fromStableParcelable(@Nullable ProxyInfoParcelable parcel) {
- if (parcel == null) {
- return null;
- }
- if (Uri.EMPTY.toString().equals(parcel.pacFileUrl)) {
- return ProxyInfo.buildDirectProxy(
- parcel.host, parcel.port, Arrays.asList(parcel.exclusionList));
- } else {
- return ProxyInfo.buildPacProxy(Uri.parse(parcel.pacFileUrl));
- }
- }
-
- /**
- * Convert an IpPrefixParcelable to an IpPrefix
- */
- public static IpPrefixParcelable toStableParcelable(@Nullable IpPrefix ipPrefix) {
- if (ipPrefix == null) {
- return null;
- }
- final IpPrefixParcelable parcel = new IpPrefixParcelable();
- parcel.address = parcelAddress(ipPrefix.getAddress());
- parcel.prefixLength = ipPrefix.getPrefixLength();
- return parcel;
- }
-
- /**
- * Convert an IpPrefix to an IpPrefixParcelable
- */
- public static IpPrefix fromStableParcelable(@Nullable IpPrefixParcelable parcel) {
- if (parcel == null) {
- return null;
- }
- return new IpPrefix(unparcelAddress(parcel.address), parcel.prefixLength);
- }
-
- /**
- * Convert a RouteInfoParcelable to a RouteInfo
- */
- public static RouteInfoParcelable toStableParcelable(@Nullable RouteInfo routeInfo) {
- if (routeInfo == null) {
- return null;
- }
- final RouteInfoParcelable parcel = new RouteInfoParcelable();
- parcel.destination = toStableParcelable(routeInfo.getDestination());
- parcel.gatewayAddr = parcelAddress(routeInfo.getGateway());
- parcel.ifaceName = routeInfo.getInterface();
- parcel.type = routeInfo.getType();
- return parcel;
- }
-
- /**
- * Convert a RouteInfo to a RouteInfoParcelable
- */
- public static RouteInfo fromStableParcelable(@Nullable RouteInfoParcelable parcel) {
- if (parcel == null) {
- return null;
- }
- final IpPrefix destination = fromStableParcelable(parcel.destination);
- return new RouteInfo(
- destination, unparcelAddress(parcel.gatewayAddr),
- parcel.ifaceName, parcel.type);
- }
-
- /**
- * Convert a LinkAddressParcelable to a LinkAddress
- */
- public static LinkAddressParcelable toStableParcelable(@Nullable LinkAddress la) {
- if (la == null) {
- return null;
- }
- final LinkAddressParcelable parcel = new LinkAddressParcelable();
- parcel.address = parcelAddress(la.getAddress());
- parcel.prefixLength = la.getPrefixLength();
- parcel.flags = la.getFlags();
- parcel.scope = la.getScope();
- return parcel;
- }
-
- /**
- * Convert a LinkAddress to a LinkAddressParcelable
- */
- public static LinkAddress fromStableParcelable(@Nullable LinkAddressParcelable parcel) {
- if (parcel == null) {
- return null;
- }
- return new LinkAddress(
- unparcelAddress(parcel.address),
- parcel.prefixLength,
- parcel.flags,
- parcel.scope);
- }
-
- /**
- * Convert a LinkProperties to a LinkPropertiesParcelable
- */
- public static LinkPropertiesParcelable toStableParcelable(@Nullable LinkProperties lp) {
- if (lp == null) {
- return null;
- }
- final LinkPropertiesParcelable parcel = new LinkPropertiesParcelable();
- parcel.ifaceName = lp.getInterfaceName();
- parcel.linkAddresses = toParcelableArray(
- lp.getLinkAddresses(),
- LinkPropertiesParcelableUtil::toStableParcelable,
- LinkAddressParcelable.class);
- parcel.dnses = toParcelableArray(
- lp.getDnsServers(), IpConfigurationParcelableUtil::parcelAddress, String.class);
- parcel.pcscfs = toParcelableArray(
- lp.getPcscfServers(), IpConfigurationParcelableUtil::parcelAddress, String.class);
- parcel.validatedPrivateDnses = toParcelableArray(lp.getValidatedPrivateDnsServers(),
- IpConfigurationParcelableUtil::parcelAddress, String.class);
- parcel.usePrivateDns = lp.isPrivateDnsActive();
- parcel.privateDnsServerName = lp.getPrivateDnsServerName();
- parcel.domains = lp.getDomains();
- parcel.routes = toParcelableArray(
- lp.getRoutes(), LinkPropertiesParcelableUtil::toStableParcelable,
- RouteInfoParcelable.class);
- parcel.httpProxy = toStableParcelable(lp.getHttpProxy());
- parcel.mtu = lp.getMtu();
- parcel.tcpBufferSizes = lp.getTcpBufferSizes();
- parcel.nat64Prefix = toStableParcelable(lp.getNat64Prefix());
- return parcel;
- }
-
- /**
- * Convert a LinkPropertiesParcelable to a LinkProperties
- */
- public static LinkProperties fromStableParcelable(@Nullable LinkPropertiesParcelable parcel) {
- if (parcel == null) {
- return null;
- }
- final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(parcel.ifaceName);
- lp.setLinkAddresses(fromParcelableArray(parcel.linkAddresses,
- LinkPropertiesParcelableUtil::fromStableParcelable));
- lp.setDnsServers(fromParcelableArray(
- parcel.dnses, IpConfigurationParcelableUtil::unparcelAddress));
- lp.setPcscfServers(fromParcelableArray(
- parcel.pcscfs, IpConfigurationParcelableUtil::unparcelAddress));
- lp.setValidatedPrivateDnsServers(
- fromParcelableArray(parcel.validatedPrivateDnses,
- IpConfigurationParcelableUtil::unparcelAddress));
- lp.setUsePrivateDns(parcel.usePrivateDns);
- lp.setPrivateDnsServerName(parcel.privateDnsServerName);
- lp.setDomains(parcel.domains);
- for (RouteInfoParcelable route : parcel.routes) {
- lp.addRoute(fromStableParcelable(route));
- }
- lp.setHttpProxy(fromStableParcelable(parcel.httpProxy));
- lp.setMtu(parcel.mtu);
- lp.setTcpBufferSizes(parcel.tcpBufferSizes);
- lp.setNat64Prefix(fromStableParcelable(parcel.nat64Prefix));
+ @Deprecated
+ public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) {
return lp;
}
+
+ /**
+ * @deprecated conversion to stable parcelable is no longer necessary.
+ */
+ @Deprecated
+ public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) {
+ return info;
+ }
}
diff --git a/services/net/java/android/net/shared/NetworkParcelableUtil.java b/services/net/java/android/net/shared/NetworkParcelableUtil.java
deleted file mode 100644
index d0b54b8..0000000
--- a/services/net/java/android/net/shared/NetworkParcelableUtil.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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 android.net.shared;
-
-import android.annotation.Nullable;
-import android.net.Network;
-import android.net.NetworkParcelable;
-
-/**
- * Utility methods to convert to/from stable AIDL parcelables for network attribute classes.
- * @hide
- */
-public final class NetworkParcelableUtil {
- /**
- * Convert from a Network to a NetworkParcelable.
- */
- public static NetworkParcelable toStableParcelable(@Nullable Network network) {
- if (network == null) {
- return null;
- }
- final NetworkParcelable p = new NetworkParcelable();
- p.networkHandle = network.getNetworkHandle();
-
- return p;
- }
-
- /**
- * Convert from a NetworkParcelable to a Network.
- */
- public static Network fromStableParcelable(@Nullable NetworkParcelable p) {
- if (p == null) {
- return null;
- }
- return Network.fromNetworkHandle(p.networkHandle);
- }
-}
diff --git a/services/net/java/android/net/shared/ProvisioningConfiguration.java b/services/net/java/android/net/shared/ProvisioningConfiguration.java
index f937065..0aceb22 100644
--- a/services/net/java/android/net/shared/ProvisioningConfiguration.java
+++ b/services/net/java/android/net/shared/ProvisioningConfiguration.java
@@ -239,7 +239,7 @@
p.apfCapabilities = IpConfigurationParcelableUtil.toStableParcelable(mApfCapabilities);
p.provisioningTimeoutMs = mProvisioningTimeoutMs;
p.ipv6AddrGenMode = mIPv6AddrGenMode;
- p.network = NetworkParcelableUtil.toStableParcelable(mNetwork);
+ p.network = mNetwork;
p.displayName = mDisplayName;
return p;
}
@@ -263,7 +263,7 @@
p.apfCapabilities);
config.mProvisioningTimeoutMs = p.provisioningTimeoutMs;
config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
- config.mNetwork = NetworkParcelableUtil.fromStableParcelable(p.network);
+ config.mNetwork = p.network;
config.mDisplayName = p.displayName;
return config;
}
diff --git a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
index 9a6e003..42115d4 100644
--- a/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/TransportManagerTest.java
@@ -554,7 +554,7 @@
transportManager.getTransportCurrentDestinationString(mTransportA1.transportName);
Intent dataManagementIntent =
transportManager.getTransportDataManagementIntent(mTransportA1.transportName);
- String dataManagementLabel =
+ CharSequence dataManagementLabel =
transportManager.getTransportDataManagementLabel(mTransportA1.transportName);
String transportDirName = transportManager.getTransportDirName(mTransportA1.transportName);
String transportDirNameByComponent =
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 f17a9fe..f4cea7a 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
@@ -326,15 +326,14 @@
}
@Test
- public void testRestoreSome_for2Packages() throws Exception {
+ public void testRestorePackages_for2Packages() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
TransportMock transportMock = setUpTransport(mTransport);
IRestoreSession restoreSession =
createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
- int result =
- restoreSession.restoreSome(
- TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2});
+ int result = restoreSession.restorePackages(TOKEN_1, mObserver,
+ new String[] {PACKAGE_1, PACKAGE_2}, mMonitor);
mShadowBackupLooper.runToEndOfTasks();
assertThat(result).isEqualTo(0);
@@ -349,27 +348,27 @@
}
@Test
- public void testRestoreSome_for2Packages_createsSystemRestoreTask() throws Exception {
+ public void testRestorePackages_for2Packages_createsSystemRestoreTask() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport);
IRestoreSession restoreSession =
createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
- restoreSession.restoreSome(
- TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2});
+ restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_1, PACKAGE_2},
+ mMonitor);
mShadowBackupLooper.runToEndOfTasks();
assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore()).isTrue();
}
@Test
- public void testRestoreSome_for1Package() throws Exception {
+ public void testRestorePackages_for1Package() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport);
IRestoreSession restoreSession =
createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
- restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+ restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_1}, mMonitor);
mShadowBackupLooper.runToEndOfTasks();
ShadowPerformUnifiedRestoreTask shadowTask =
@@ -379,13 +378,13 @@
}
@Test
- public void testRestoreSome_for1Package_createsNonSystemRestoreTask() throws Exception {
+ public void testRestorePackages_for1Package_createsNonSystemRestoreTask() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport);
IRestoreSession restoreSession =
createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
- restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+ restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_1}, mMonitor);
mShadowBackupLooper.runToEndOfTasks();
assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore())
@@ -393,32 +392,32 @@
}
@Test
- public void testRestoreSome_whenNoRestoreSets() throws Exception {
+ public void testRestorePackages_whenNoRestoreSets() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport);
IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport);
- int result =
- restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+ int result = restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_1},
+ mMonitor);
assertThat(result).isEqualTo(-1);
}
@Test
- public void testRestoreSome_whenSinglePackageSession() throws Exception {
+ public void testRestorePackages_whenSinglePackageSession() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport);
IRestoreSession restoreSession =
createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1);
- int result =
- restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_2});
+ int result = restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_2},
+ mMonitor);
assertThat(result).isEqualTo(-1);
}
@Test
- public void testRestoreSome_whenSessionEnded() throws Exception {
+ public void testRestorePackages_whenSessionEnded() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport);
IRestoreSession restoreSession =
@@ -429,19 +428,19 @@
expectThrows(
IllegalStateException.class,
() ->
- restoreSession.restoreSome(
- TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1}));
+ restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_1},
+ mMonitor));
}
@Test
- public void testRestoreSome_whenTransportNotRegistered() throws Exception {
+ public void testRestorePackages_whenTransportNotRegistered() throws Exception {
mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP);
setUpTransport(mTransport.unregistered());
IRestoreSession restoreSession =
createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1);
- int result =
- restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1});
+ int result = restoreSession.restorePackages(TOKEN_1, mObserver, new String[] {PACKAGE_1},
+ mMonitor);
assertThat(result).isEqualTo(-1);
}
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java b/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java
index 77f5d9a4..3c29810 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/TransportData.java
@@ -75,7 +75,7 @@
@Nullable public Intent configurationIntent;
@Nullable public String currentDestinationString;
@Nullable public Intent dataManagementIntent;
- @Nullable public String dataManagementLabel;
+ @Nullable public CharSequence dataManagementLabel;
private TransportData(
@TransportStatus int transportStatus,
@@ -85,7 +85,7 @@
Intent configurationIntent,
String currentDestinationString,
Intent dataManagementIntent,
- String dataManagementLabel) {
+ CharSequence dataManagementLabel) {
this.transportStatus = transportStatus;
this.transportName = transportName;
this.transportComponentShort = transportComponentShort;
@@ -103,7 +103,7 @@
Intent configurationIntent,
String currentDestinationString,
Intent dataManagementIntent,
- String dataManagementLabel) {
+ CharSequence dataManagementLabel) {
this(
TransportStatus.REGISTERED_AVAILABLE,
transportName,
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java
index f6ed630..7dd5be5 100644
--- a/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java
+++ b/services/robotests/backup/src/com/android/server/backup/testing/TransportTestUtils.java
@@ -188,7 +188,8 @@
when(transportBinder.currentDestinationString())
.thenReturn(transport.currentDestinationString);
when(transportBinder.dataManagementIntent()).thenReturn(transport.dataManagementIntent);
- when(transportBinder.dataManagementLabel()).thenReturn(transport.dataManagementLabel);
+ when(transportBinder.dataManagementIntentLabel())
+ .thenReturn(transport.dataManagementLabel);
} catch (RemoteException e) {
fail("RemoteException?");
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 6386b3b3..7c91b64 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -15,7 +15,10 @@
*/
package com.android.server;
+import static android.app.AlarmManager.ELAPSED_REALTIME;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
@@ -254,14 +257,22 @@
}
private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
+ setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID);
+ }
+
+ private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) {
mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
- TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+ callingUid, TEST_CALLING_PACKAGE);
}
private PendingIntent getNewMockPendingIntent() {
+ return getNewMockPendingIntent(TEST_CALLING_UID);
+ }
+
+ private PendingIntent getNewMockPendingIntent(int mockUid) {
final PendingIntent mockPi = mock(PendingIntent.class, Answers.RETURNS_DEEP_STUBS);
- when(mockPi.getCreatorUid()).thenReturn(TEST_CALLING_UID);
+ when(mockPi.getCreatorUid()).thenReturn(mockUid);
when(mockPi.getCreatorPackage()).thenReturn(TEST_CALLING_PACKAGE);
return mockPi;
}
@@ -724,6 +735,91 @@
verify(mMockContext).sendBroadcastAsUser(mService.mTimeTickIntent, UserHandle.ALL);
}
+ @Test
+ public void alarmCountKeyedOnCallingUid() {
+ final int mockCreatorUid = 431412;
+ final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi);
+ assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1));
+ }
+
+ @Test
+ public void alarmCountOnSet() {
+ final int numAlarms = 103;
+ final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
+ for (int i = 1; i <= numAlarms; i++) {
+ setTestAlarm(types[i % 4], mNowElapsedTest + i, getNewMockPendingIntent());
+ assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ }
+ }
+
+ @Test
+ public void alarmCountOnExpiration() throws InterruptedException {
+ final int numAlarms = 8; // This test is slow
+ for (int i = 0; i < numAlarms; i++) {
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+ }
+ int expired = 0;
+ while (expired < numAlarms) {
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ expired++;
+ assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ }
+
+ @Test
+ public void alarmCountOnUidRemoved() {
+ final int numAlarms = 10;
+ for (int i = 0; i < numAlarms; i++) {
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ mService.removeLocked(TEST_CALLING_UID);
+ assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+
+ @Test
+ public void alarmCountOnPackageRemoved() {
+ final int numAlarms = 10;
+ for (int i = 0; i < numAlarms; i++) {
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ mService.removeLocked(TEST_CALLING_PACKAGE);
+ assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+
+ @Test
+ public void alarmCountOnUserRemoved() {
+ final int mockUserId = 15;
+ final int numAlarms = 10;
+ for (int i = 0; i < numAlarms; i++) {
+ int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
+ getNewMockPendingIntent(mockUid), mockUid);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.size());
+ mService.removeUserLocked(mockUserId);
+ assertEquals(0, mService.mAlarmsPerUid.size());
+ }
+
+ @Test
+ public void alarmCountOnAlarmRemoved() {
+ final int numAlarms = 10;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ for (int i = 0; i < numAlarms; i++) {
+ mService.removeLocked(pis[i], null);
+ assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 8e78a56..c45122e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -52,6 +52,7 @@
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkPolicyManager;
import android.os.Build;
+import android.os.Looper;
import android.os.SystemClock;
import android.util.DataUnit;
@@ -102,6 +103,8 @@
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(NetworkPolicyManagerInternal.class, mNetPolicyManagerInternal);
+ when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
+
// Freeze the clocks at this moment in time
JobSchedulerService.sSystemClock =
Clock.fixed(Clock.systemUTC().instant(), ZoneOffset.UTC);
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index 86e8598..2e5efbd 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -28,6 +28,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.os.PowerManager;
import android.provider.Settings.Global;
import androidx.test.filters.SmallTest;
@@ -452,6 +453,21 @@
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
+
+ // Disable auto battery saver.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ mDevice.setBatteryLevel(25);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(25, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // PowerManager sets batteryLow to true at 15% if battery saver trigger level is lower.
+ mDevice.setBatteryLevel(15);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(15, mPersistedState.batteryLevel);
+ assertEquals(true, mPersistedState.batteryLow);
}
@Test
@@ -542,6 +558,12 @@
assertEquals(100, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
+ mDevice.setBatteryLevel(97);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+ assertEquals(97, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
mDevice.setBatteryLevel(95);
assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
@@ -719,6 +741,48 @@
}
@Test
+ public void testAutoBatterySaver_withSticky_withAutoOffToggled() {
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, 90);
+
+ // Scenario 1: User turns BS on manually above the threshold, it shouldn't turn off even
+ // with battery level change above threshold.
+ mDevice.setBatteryLevel(100);
+ mTarget.setBatterySaverEnabledManually(true);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ mDevice.setBatteryLevel(95);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Stays on.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Disable auto disable while in the pending sticky state. BS should reactivate after
+ // unplug.
+ mDevice.setPowered(true);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 0);
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Sticky BS should activate.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+
+ // Enable auto disable while in the pending sticky state. Sticky should turn off after
+ // unplug.
+ mDevice.setPowered(true);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
+ mDevice.setPowered(false);
+
+ assertEquals(false, mDevice.batterySaverEnabled); // Sticky BS no longer enabled.
+ assertEquals(95, mPersistedState.batteryLevel);
+ assertEquals(false, mPersistedState.batteryLow);
+ }
+
+ @Test
public void testAutoBatterySaver_withStickyDisabled() {
when(mMockResources.getBoolean(
com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
@@ -739,7 +803,9 @@
assertEquals(30, mPersistedState.batteryLevel);
assertEquals(true, mPersistedState.batteryLow);
+ mDevice.setPowered(true);
mDevice.setBatteryLevel(80);
+ mDevice.setPowered(false);
assertEquals(false, mDevice.batterySaverEnabled); // Not sticky.
assertEquals(80, mPersistedState.batteryLevel);
@@ -830,10 +896,9 @@
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
- // Reboot -- setting BS from adb is also sticky.
+ // Reboot -- LOW_POWER_MODE shouldn't be persisted.
initDevice();
-
- assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(90, mPersistedState.batteryLevel);
assertEquals(false, mPersistedState.batteryLow);
}
@@ -841,7 +906,8 @@
@Test
public void testAutoBatterySaver_smartBatterySaverEnabled() {
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
- mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE, 1);
+ mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
assertEquals(false, mDevice.batterySaverEnabled);
@@ -922,8 +988,8 @@
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 71);
mDevice.setBatteryLevel(mPersistedState.batteryLevel);
- // changes are only registered if some battery level changed
- assertEquals(false, mDevice.batterySaverEnabled);
+ // Changes should register immediately.
+ assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(70, mPersistedState.batteryLevel);
mDevice.setBatteryLevel(69);
@@ -935,8 +1001,8 @@
mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 60);
mDevice.setBatteryLevel(mPersistedState.batteryLevel);
- // changes are only registered if battery level changed
- assertEquals(true, mDevice.batterySaverEnabled);
+ // Changes should register immediately.
+ assertEquals(false, mDevice.batterySaverEnabled);
assertEquals(69, mPersistedState.batteryLevel);
mDevice.setBatteryLevel(68);
@@ -956,4 +1022,220 @@
assertEquals(true, mDevice.batterySaverEnabled);
assertEquals(30, mPersistedState.batteryLevel);
}
+
+ @Test
+ public void testAutoBatterySaver_snoozed_autoEnabled() {
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 30);
+ // Test dynamic threshold higher than automatic to make sure it doesn't interfere when it's
+ // not enabled.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+ mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_PERCENTAGE);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(90);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(51);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(51, mPersistedState.batteryLevel);
+
+ // Hit dynamic threshold. BS should be disabled since dynamic is off
+ mDevice.setBatteryLevel(50);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(50, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(20);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold. Level is still below, so should still be snoozed.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 25);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+ // disabled.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 10);
+ // "batteryLow" is set in setBatteryLevel.
+ mDevice.setBatteryLevel(19);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(19, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(10);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ // Plug in and out, snooze will reset.
+ mDevice.setPowered(true);
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(60);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(60, mPersistedState.batteryLevel);
+
+ // Test toggling resets snooze.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.setPowered(false);
+ mDevice.setBatteryLevel(45);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ // Disable and re-enable.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+ assertEquals(45, mPersistedState.batteryLevel);
+ }
+
+ @Test
+ public void testAutoBatterySaver_snoozed_dynamicEnabled() {
+ // Test auto threshold higher than dynamic to make sure it doesn't interfere when it's
+ // not enabled.
+ mDevice.putGlobalSetting(Global.LOW_POWER_MODE_TRIGGER_LEVEL, 50);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 30);
+ mDevice.putGlobalSetting(Global.AUTOMATIC_POWER_SAVER_MODE,
+ PowerManager.POWER_SAVER_MODE_DYNAMIC);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(100, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(90);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(90, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(51);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(51, mPersistedState.batteryLevel);
+
+ // Hit automatic threshold. BS should be disabled since automatic is off
+ mDevice.setBatteryLevel(50);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(50, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(30);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(30, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(20);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold. Level is still below, so should still be snoozed.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 25);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ // Lower threshold even more. Battery no longer considered "low" so snoozing should be
+ // disabled.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 10);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(20, mPersistedState.batteryLevel);
+
+ mDevice.setBatteryLevel(10);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // No longer snoozing.
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+
+ // Plug in and out, snooze will reset.
+ mDevice.setPowered(true);
+ mDevice.setPowered(false);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(10, mPersistedState.batteryLevel);
+
+ mDevice.setPowered(true);
+ mDevice.setBatteryLevel(60);
+
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(60, mPersistedState.batteryLevel);
+
+ // Test toggling resets snooze.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD, 50);
+ mDevice.setPowered(false);
+ mDevice.setBatteryLevel(45);
+
+ assertEquals(true, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ mTarget.setBatterySaverEnabledManually(false); // Manually disable -> snooze.
+ assertEquals(false, mDevice.batterySaverEnabled);
+ assertEquals(45, mPersistedState.batteryLevel);
+
+ // Disable and re-enable.
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 0);
+ mDevice.putGlobalSetting(Global.DYNAMIC_POWER_SAVINGS_ENABLED, 1);
+
+ assertEquals(true, mDevice.batterySaverEnabled); // Snooze reset
+ assertEquals(45, mPersistedState.batteryLevel);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 3e5ce46..dd79aad 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -82,7 +82,7 @@
private static final String CURRENT_PASSWORD = "current_password";
private static final String NEW_PASSWORD = "new_password";
private static final String ENCRYPTION_PASSWORD = "encryption_password";
- private static final String DATA_MANAGEMENT_LABEL = "data_management_label";
+ private static final CharSequence DATA_MANAGEMENT_LABEL = "data_management_label";
private static final String DESTINATION_STRING = "destination_string";
private static final String[] PACKAGE_NAMES =
new String[]{"some.package.name._1", "some.package.name._2"};
@@ -1104,8 +1104,8 @@
}
@Test
- public void getDataManagementLabel_calledBeforeInitialize_ignored() throws Exception {
- assertNull(mTrampoline.getDataManagementLabel(TRANSPORT_NAME));
+ public void getDataManagementLabelForUser_calledBeforeInitialize_ignored() throws Exception {
+ assertNull(mTrampoline.getDataManagementLabelForUser(mUserId, TRANSPORT_NAME));
verifyNoMoreInteractions(mBackupManagerServiceMock);
}
@@ -1122,17 +1122,6 @@
}
@Test
- public void getDataManagementLabel_forwarded() throws Exception {
- TrampolineTestable.sCallingUserId = mUserId;
- when(mBackupManagerServiceMock.getDataManagementLabel(mUserId, TRANSPORT_NAME)).thenReturn(
- DATA_MANAGEMENT_LABEL);
- mTrampoline.initializeService();
-
- assertEquals(DATA_MANAGEMENT_LABEL, mTrampoline.getDataManagementLabel(TRANSPORT_NAME));
- verify(mBackupManagerServiceMock).getDataManagementLabel(mUserId, TRANSPORT_NAME);
- }
-
- @Test
public void beginRestoreSession_calledBeforeInitialize_ignored() throws Exception {
mTrampoline.beginRestoreSessionForUser(mUserId, PACKAGE_NAME, TRANSPORT_NAME);
verifyNoMoreInteractions(mBackupManagerServiceMock);
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 26b1224..caf6c9c 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -1138,7 +1138,7 @@
}
@Override
- public String getContentCaptureServicePackageName() throws RemoteException {
+ public String getSystemCaptionsServicePackageName() throws RemoteException {
return null;
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 77515258..6a07a45 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -338,12 +338,15 @@
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
+ assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertTrue(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
PRIMARY_USER_ID).getResponseCode();
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
+ assertFalse(mService.hasPendingEscrowToken(PRIMARY_USER_ID));
mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
deleted file mode 100644
index d7dc58d..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/LauncherAppsServiceTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.pm;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.pm.PackageParser;
-import android.content.pm.Signature;
-import android.content.pm.SigningInfo;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnitRunner;
-
-@Presubmit
-@RunWith(MockitoJUnitRunner.class)
-public class LauncherAppsServiceTest {
-
- private static final Signature SIGNATURE_1 = new Signature(new byte[]{0x00, 0x01, 0x02, 0x03});
- private static final Signature SIGNATURE_2 = new Signature(new byte[]{0x04, 0x05, 0x06, 0x07});
- private static final Signature SIGNATURE_3 = new Signature(new byte[]{0x08, 0x09, 0x10, 0x11});
-
- @Test
- public void testComputePackageCertDigest() {
- String digest = LauncherAppsService.LauncherAppsImpl.computePackageCertDigest(SIGNATURE_1);
- assertEquals("A02A05B025B928C039CF1AE7E8EE04E7C190C0DB", digest);
- }
-
- @Test
- public void testGetLatestSignaturesWithSingleCert() {
- SigningInfo signingInfo = new SigningInfo(
- new PackageParser.SigningDetails(
- new Signature[]{SIGNATURE_1},
- PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
- null,
- null));
- Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
- signingInfo);
- assertEquals(1, signatures.length);
- assertEquals(SIGNATURE_1, signatures[0]);
- }
-
- @Test
- public void testGetLatestSignaturesWithMultiCert() {
- SigningInfo signingInfo = new SigningInfo(
- new PackageParser.SigningDetails(
- new Signature[]{SIGNATURE_1, SIGNATURE_2},
- PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
- null,
- null));
- Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
- signingInfo);
- assertEquals(2, signatures.length);
- assertEquals(SIGNATURE_1, signatures[0]);
- assertEquals(SIGNATURE_2, signatures[1]);
- }
-
- @Test
- public void testGetLatestSignaturesWithCertHistory() {
- SigningInfo signingInfo = new SigningInfo(
- new PackageParser.SigningDetails(
- new Signature[]{SIGNATURE_1},
- PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
- null,
- new Signature[]{SIGNATURE_2, SIGNATURE_3}));
- Signature[] signatures = LauncherAppsService.LauncherAppsImpl.getLatestSignatures(
- signingInfo);
- assertEquals(1, signatures.length);
- assertEquals(SIGNATURE_2, signatures[0]);
- }
-
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 9504381..fa1bcac 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -35,6 +35,7 @@
import android.app.Person;
import android.content.ComponentName;
import android.content.Intent;
+import android.content.LocusId;
import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
@@ -250,7 +251,7 @@
.setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
.setRank(123)
.setPerson(makePerson("person", "personKey", "personUri"))
- .setLongLived()
+ .setLongLived(true)
.setExtras(pb)
.build();
si.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -352,7 +353,7 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setPerson(makePerson("person", "personKey", "personUri"))
- .setLongLived()
+ .setLongLived(true)
.setExtras(pb)
.build();
sorig.addFlags(ShortcutInfo.FLAG_PINNED);
@@ -895,6 +896,7 @@
.setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
.setRank(123)
.setExtras(pb)
+ .setLocusId(new LocusId("1.2.3.4.5"))
.build();
sorig.setTimestamp(mInjectedCurrentTimeMillis);
@@ -906,6 +908,7 @@
.setPersons(list(makePerson("person1", "personKey1", "personUri1"),
makePerson("person2", "personKey2", "personUri2")).toArray(new Person[2]))
.setRank(456)
+ .setLocusId(new LocusId("6.7.8.9"))
.build();
sorig2.setTimestamp(mInjectedCurrentTimeMillis);
@@ -946,6 +949,7 @@
assertEquals("personUri", si.getPersons()[0].getUri());
assertEquals(0, si.getRank());
assertEquals(1, si.getExtras().getInt("k"));
+ assertEquals("1.2.3.4.5", si.getLocusId().getId());
assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
| ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
@@ -959,6 +963,7 @@
assertEquals(1, si.getRank());
assertEquals(2, si.getPersons().length);
assertEquals("personUri2", si.getPersons()[1].getUri());
+ assertEquals("6.7.8.9", si.getLocusId().getId());
dumpUserFile(USER_10);
}
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index a2f1f01..a1a58b4 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -105,6 +105,13 @@
}
@Test
+ public void testOnUserActivity_doesntCrashIfNoAttentionService() {
+ mAttentionManagerInternal = null;
+ registerAttention();
+ // Does not crash.
+ }
+
+ @Test
public void onUserActivity_ignoresWhiteListedActivityTypes() {
for (int i = 0; i < NUM_USER_ACTIVITY_TYPES; i++) {
int result = mAttentionDetector.onUserActivity(SystemClock.uptimeMillis(), i);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 4626840..a8da80e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -37,6 +37,7 @@
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
@@ -111,6 +112,7 @@
import android.testing.TestableContext;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestablePermissions;
import android.text.Html;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -389,7 +391,8 @@
mBinderService.createNotificationChannels(
PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
- assertNotNull(mBinderService.getNotificationChannel(PKG, TEST_CHANNEL_ID));
+ assertNotNull(mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
}
@After
@@ -495,7 +498,7 @@
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel(PKG, "id");
+ mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
assertTrue(createdChannel != null);
}
@@ -518,8 +521,10 @@
new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT);
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
- assertTrue(mBinderService.getNotificationChannel(PKG, "id1") != null);
- assertTrue(mBinderService.getNotificationChannel(PKG, "id2") != null);
+ assertTrue(mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, "id1") != null);
+ assertTrue(mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, "id2") != null);
}
@Test
@@ -536,7 +541,7 @@
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel(PKG, "id");
+ mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
}
@@ -554,7 +559,7 @@
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel(PKG, "id");
+ mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance());
}
@@ -577,7 +582,7 @@
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(dupeChannel)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel(PKG, "id");
+ mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
}
@@ -591,7 +596,7 @@
mBinderService.createNotificationChannels(PKG,
new ParceledListSlice(Arrays.asList(channel1, channel2)));
final NotificationChannel createdChannel =
- mBinderService.getNotificationChannel(PKG, "id");
+ mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance());
}
@@ -644,8 +649,8 @@
assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
assertEquals(IMPORTANCE_LOW,
mService.getNotificationRecord(sbn.getKey()).getImportance());
- assertEquals(IMPORTANCE_LOW,
- mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
}
@Test
@@ -662,8 +667,8 @@
new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
waitForIdle();
- assertEquals(IMPORTANCE_NONE,
- mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -675,8 +680,8 @@
assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
assertEquals(IMPORTANCE_LOW,
mService.getNotificationRecord(sbn.getKey()).getImportance());
- assertEquals(IMPORTANCE_LOW,
- mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
waitForIdle();
@@ -684,8 +689,8 @@
update.setFgServiceShown(true);
mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
waitForIdle();
- assertEquals(IMPORTANCE_NONE,
- mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
sbn = generateNotificationRecord(channel).sbn;
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -695,8 +700,8 @@
// The second time it is shown, we keep the user's preference.
assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
assertNull(mService.getNotificationRecord(sbn.getKey()));
- assertEquals(IMPORTANCE_NONE,
- mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+ assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel(
+ PKG, mContext.getUserId(), PKG, channel.getId()).getImportance());
}
@Test
@@ -2690,7 +2695,7 @@
mService.getNotificationRecord(sbn.getKey()).getImportance());
NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
- preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
+ preOPkg, mContext.getUserId(), preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
}
@@ -4171,6 +4176,44 @@
}
@Test
+ public void testCanNotifyAsUser_crossUser() throws Exception {
+ // same user no problem
+ mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId());
+
+ // cross user, no permission, problem
+ try {
+ mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
+ fail("Should not be callable cross user without cross user permission");
+ } catch (SecurityException e) {
+ // good
+ }
+
+ // cross user, with permission, no problem
+ TestablePermissions perms = mContext.getTestablePermissions();
+ perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
+ mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1);
+ }
+
+ @Test
+ public void testgetNotificationChannels_crossUser() throws Exception {
+ // same user no problem
+ mBinderService.getNotificationChannels("src", "target", mContext.getUserId());
+
+ // cross user, no permission, problem
+ try {
+ mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
+ fail("Should not be callable cross user without cross user permission");
+ } catch (SecurityException e) {
+ // good
+ }
+
+ // cross user, with permission, no problem
+ TestablePermissions perms = mContext.getTestablePermissions();
+ perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
+ mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1);
+ }
+
+ @Test
public void setDefaultAssistantForUser_fromConfigXml() {
clearDeviceConfig();
ComponentName xmlConfig = new ComponentName("config", "xml");
@@ -4243,4 +4286,18 @@
componentName,
false);
}
+
+ public void testGetAllowedAssistantCapabilities() throws Exception {
+ List<String> capabilities = mBinderService.getAllowedAssistantCapabilities(null);
+ assertNotNull(capabilities);
+
+ for (int i = capabilities.size() - 1; i >= 0; i--) {
+ String capability = capabilities.get(i);
+ mBinderService.disallowAssistantCapability(capability);
+ assertEquals(i + 1, mBinderService.getAllowedAssistantCapabilities(null).size());
+ List<String> currentCapabilities = mBinderService.getAllowedAssistantCapabilities(null);
+ assertNotNull(currentCapabilities);
+ assertFalse(currentCapabilities.contains(capability));
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 59e71c4..9583b8ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -18,32 +18,26 @@
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.contains;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import android.app.WaitResult;
+import android.content.pm.ActivityInfo;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.MediumTest;
@@ -112,4 +106,44 @@
assertEquals(deliverToTopWait.who, firstActivity.mActivityComponent);
}
}
+
+ /**
+ * Ensures that {@link TaskChangeNotificationController} notifies only when an activity is
+ * forced to resize on secondary display.
+ */
+ @Test
+ public void testHandleNonResizableTaskOnSecondaryDisplay() {
+ // Create an unresizable task on secondary display.
+ final ActivityDisplay newDisplay = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+ .setDisplay(newDisplay).build();
+ final ActivityRecord unresizableActivity = stack.getTopActivity();
+ final TaskRecord task = unresizableActivity.getTaskRecord();
+ unresizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+ task.setResizeMode(unresizableActivity.info.resizeMode);
+
+ final TaskChangeNotificationController taskChangeNotifier =
+ mService.getTaskChangeNotificationController();
+ spyOn(taskChangeNotifier);
+
+ mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
+ newDisplay.mDisplayId, stack);
+ // The top activity is unresizable, so it should notify the activity is forced resizing.
+ verify(taskChangeNotifier).notifyActivityForcedResizable(eq(task.taskId),
+ eq(FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY),
+ eq(unresizableActivity.packageName));
+ reset(taskChangeNotifier);
+
+ // Put a resizable activity on top of the unresizable task.
+ final ActivityRecord resizableActivity = new ActivityBuilder(mService)
+ .setTask(task).build();
+ resizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+
+ mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(),
+ newDisplay.mDisplayId, stack);
+ // For the resizable activity, it is no need to force resizing or dismiss the docked stack.
+ verify(taskChangeNotifier, never()).notifyActivityForcedResizable(anyInt() /* taskId */,
+ anyInt() /* reason */, anyString() /* packageName */);
+ verify(taskChangeNotifier, never()).notifyActivityDismissingDockedStack();
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
index 5556a15..febb795 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingAppWindowTokenRegistryTest.java
@@ -43,7 +43,6 @@
*/
@SmallTest
@Presubmit
-@FlakyTest(detail = "Promote once confirmed non-flaky")
public class AnimatingAppWindowTokenRegistryTest extends WindowTestsBase {
@Mock
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 81133d1..9bd9930 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -17,12 +17,16 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import android.platform.test.annotations.Presubmit;
import android.view.WindowManager;
@@ -95,4 +99,24 @@
TRANSIT_TASK_CHANGE_WINDOWING_MODE));
}
}
+
+ @Test
+ public void testTransitWithinTask() {
+ synchronized (mWm.mGlobalLock) {
+ final AppWindowToken opening = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ opening.setFillsParent(false);
+ final AppWindowToken closing = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ closing.setFillsParent(false);
+ Task task = opening.getTask();
+ mDisplayContent.mOpeningApps.add(opening);
+ mDisplayContent.mClosingApps.add(closing);
+ assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
+ closing.getTask().removeChild(closing);
+ task.addChild(closing, 0);
+ assertTrue(mAppTransitionController.isTransitWithinTask(TRANSIT_ACTIVITY_OPEN, task));
+ assertFalse(mAppTransitionController.isTransitWithinTask(TRANSIT_TASK_OPEN, task));
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
index 1e02a12..329af95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AssistDataRequesterTest.java
@@ -38,9 +38,7 @@
import static org.mockito.ArgumentMatchers.eq;
import android.app.AppOpsManager;
-import android.app.IActivityManager;
import android.app.IActivityTaskManager;
-import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
@@ -50,7 +48,6 @@
import android.util.Log;
import android.view.IWindowManager;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.server.am.AssistDataRequester;
@@ -88,12 +85,10 @@
private static final int TEST_UID = 0;
private static final String TEST_PACKAGE = "";
- private Context mContext;
private AssistDataRequester mDataRequester;
private Callbacks mCallbacks;
private Object mCallbacksLock;
private Handler mHandler;
- private IActivityManager mAm;
private IActivityTaskManager mAtm;
private IWindowManager mWm;
private AppOpsManager mAppOpsManager;
@@ -109,7 +104,6 @@
@Before
public void setUp() throws Exception {
- mAm = mock(IActivityManager.class);
mAtm = mock(IActivityTaskManager.class);
mWm = mock(IWindowManager.class);
mAppOpsManager = mock(AppOpsManager.class);
@@ -118,7 +112,7 @@
mCallbacks = new Callbacks();
mDataRequester = new AssistDataRequester(mContext, mWm, mAppOpsManager, mCallbacks,
mCallbacksLock, OP_ASSIST_STRUCTURE, OP_ASSIST_SCREENSHOT);
-
+ mDataRequester.mActivityTaskManager = mAtm;
// Gate the continuation of the assist data callbacks until we are ready within the tests
mGate = new CountDownLatch(1);
doAnswer(invocation -> {
@@ -155,7 +149,6 @@
.checkOpNoThrow(eq(OP_ASSIST_SCREENSHOT), anyInt(), anyString());
}
- @FlakyTest(bugId = 124088319)
@Test
public void testRequestData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -176,7 +169,6 @@
assertReceivedDataCount(0, 0, 0, 0);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -187,7 +179,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testProcessPendingData() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -245,7 +236,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistContextExtras_expectNullDataCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -259,7 +249,6 @@
assertReceivedDataCount(0, 1, 0, 1);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testNoFetchScreenshots_expectNoScreenshotCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
@@ -270,7 +259,6 @@
assertReceivedDataCount(5, 5, 0, 0);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testDisallowAssistScreenshot_expectNullScreenshotCallback() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 98333b2..e60e54c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -25,6 +25,8 @@
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -58,12 +60,15 @@
import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.graphics.Region;
import android.metrics.LogMaker;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
+import android.util.MutableBoolean;
import android.view.DisplayCutout;
import android.view.Gravity;
+import android.view.ISystemGestureExclusionListener;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.ViewRootImpl;
@@ -683,6 +688,60 @@
}
@Test
+ public void testUpdateSystemGestureExclusion() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+ win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
+
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+ win.setHasSurface(true);
+ dc.updateSystemGestureExclusion();
+
+ final MutableBoolean invoked = new MutableBoolean(false);
+ final ISystemGestureExclusionListener.Stub verifier =
+ new ISystemGestureExclusionListener.Stub() {
+ @Override
+ public void onSystemGestureExclusionChanged(int displayId, Region actual) {
+ Region expected = Region.obtain();
+ expected.set(10, 20, 30, 40);
+ assertEquals(expected, actual);
+ invoked.value = true;
+ }
+ };
+ try {
+ dc.registerSystemGestureExclusionListener(verifier);
+ } finally {
+ dc.unregisterSystemGestureExclusionListener(verifier);
+ }
+ assertTrue("SystemGestureExclusionListener was not invoked", invoked.value);
+ }
+
+ @Test
+ public void testCalculateSystemGestureExclusion() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+ win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ win.setSystemGestureExclusion(Collections.singletonList(new Rect(10, 20, 30, 40)));
+
+ final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "win2");
+ win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ win2.setSystemGestureExclusion(Collections.singletonList(new Rect(20, 30, 40, 50)));
+
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+ win.setHasSurface(true);
+ win2.setHasSurface(true);
+
+ final Region expected = Region.obtain();
+ expected.set(20, 30, 40, 50);
+ assertEquals(expected, dc.calculateSystemGestureExclusion());
+ }
+
+ @Test
public void testOrientationChangeLogging() {
MetricsLogger mockLogger = mock(MetricsLogger.class);
Configuration oldConfig = new Configuration();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 2dad187..9a8a732 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -148,6 +148,19 @@
}
@Test
+ public void testPrimaryDisplayUpdateToFreeform_HasFreeformSupport_IsPc() {
+ mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
+
+ mWm.setSupportsFreeformWindowManagement(true);
+ mWm.setIsPc(true);
+
+ mTarget.updateSettingsForDisplay(mPrimaryDisplay);
+
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
+ mPrimaryDisplay.getWindowingMode());
+ }
+
+ @Test
public void testSecondaryDisplayDefaultToFullscreen_NoFreeformSupport() {
mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index fc1eb1c..68e7470 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -583,6 +583,114 @@
}
@Test
+ public void testFreezeTaskListOrder_reorderExistingTask() {
+ // Add some tasks
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(mTasks.get(1));
+ mRecentTasks.add(mTasks.get(2));
+ mRecentTasks.add(mTasks.get(3));
+ mRecentTasks.add(mTasks.get(4));
+ mCallbacksRecorder.clear();
+
+ // Freeze the list
+ mRecentTasks.setFreezeTaskListReordering();
+ assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Relaunch a few tasks
+ mRecentTasks.add(mTasks.get(3));
+ mRecentTasks.add(mTasks.get(2));
+
+ // Commit the task ordering with a specific task focused
+ mRecentTasks.resetFreezeTaskListReordering(mTasks.get(2));
+ assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Ensure that the order of the task list is the same as before, but with the focused task
+ // at the front
+ assertRecentTasksOrder(mTasks.get(2),
+ mTasks.get(4),
+ mTasks.get(3),
+ mTasks.get(1),
+ mTasks.get(0));
+
+ assertThat(mCallbacksRecorder.mAdded).isEmpty();
+ assertThat(mCallbacksRecorder.mTrimmed).isEmpty();
+ assertThat(mCallbacksRecorder.mRemoved).isEmpty();
+ }
+
+ @Test
+ public void testFreezeTaskListOrder_addRemoveTasks() {
+ // Add some tasks
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(mTasks.get(1));
+ mRecentTasks.add(mTasks.get(2));
+ mCallbacksRecorder.clear();
+
+ // Freeze the list
+ mRecentTasks.setFreezeTaskListReordering();
+ assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Add and remove some tasks
+ mRecentTasks.add(mTasks.get(3));
+ mRecentTasks.add(mTasks.get(4));
+ mRecentTasks.remove(mTasks.get(0));
+ mRecentTasks.remove(mTasks.get(1));
+
+ // Unfreeze the list
+ mRecentTasks.resetFreezeTaskListReordering(null);
+ assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Ensure that the order of the task list accounts for the added and removed tasks (added
+ // at the end)
+ assertRecentTasksOrder(mTasks.get(4),
+ mTasks.get(3),
+ mTasks.get(2));
+
+ assertThat(mCallbacksRecorder.mAdded).hasSize(2);
+ assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(3));
+ assertThat(mCallbacksRecorder.mAdded).contains(mTasks.get(4));
+ assertThat(mCallbacksRecorder.mRemoved).hasSize(2);
+ assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(0));
+ assertThat(mCallbacksRecorder.mRemoved).contains(mTasks.get(1));
+ }
+
+ @Test
+ public void testFreezeTaskListOrder_timeout() {
+ // Add some tasks
+ mRecentTasks.add(mTasks.get(0));
+ mRecentTasks.add(mTasks.get(1));
+ mRecentTasks.add(mTasks.get(2));
+ mRecentTasks.add(mTasks.get(3));
+ mRecentTasks.add(mTasks.get(4));
+
+ // Freeze the list
+ long freezeTime = SystemClock.elapsedRealtime();
+ mRecentTasks.setFreezeTaskListReordering();
+ assertTrue(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Relaunch a few tasks
+ mRecentTasks.add(mTasks.get(2));
+ mRecentTasks.add(mTasks.get(1));
+
+ // Override the freeze timeout params to simulate the timeout (simulate the freeze at 100ms
+ // ago with a timeout of 1ms)
+ mRecentTasks.setFreezeTaskListTimeoutParams(freezeTime - 100, 1);
+
+ ActivityStack stack = mTasks.get(2).getStack();
+ stack.moveToFront("", mTasks.get(2));
+ doReturn(stack).when(mTestService.mRootActivityContainer).getTopDisplayFocusedStack();
+ mRecentTasks.resetFreezeTaskListReorderingOnTimeout();
+ assertFalse(mRecentTasks.isFreezeTaskListReorderingSet());
+
+ // Ensure that the order of the task list is the same as before, but with the focused task
+ // at the front
+ assertRecentTasksOrder(mTasks.get(2),
+ mTasks.get(4),
+ mTasks.get(3),
+ mTasks.get(1),
+ mTasks.get(0));
+ }
+
+ @Test
public void testBackStackTasks_expectNoTrim() {
mRecentTasks.setParameters(-1 /* min */, 1 /* max */, -1 /* ms */);
@@ -721,6 +829,18 @@
true /* showRecents */));
}
+ /**
+ * Ensures that the recent tasks list is in the provided order. Note that the expected tasks
+ * should be ordered from least to most recent.
+ */
+ private void assertRecentTasksOrder(TaskRecord... expectedTasks) {
+ ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+ assertTrue(expectedTasks.length == tasks.size());
+ for (int i = 0; i < tasks.size(); i++) {
+ assertTrue(expectedTasks[i] == tasks.get(i));
+ }
+ }
+
private void assertNotRestoreTask(Runnable action) {
// Verify stack count doesn't change because task with fullscreen mode and standard type
// would have its own stack.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index a03d28b..e392353 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -20,17 +20,23 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import android.os.Binder;
@@ -67,7 +73,11 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
-
+ synchronized (mWm.mGlobalLock) {
+ // Hold the lock to protect the stubbing from being accessed by other threads.
+ spyOn(mWm.mRoot);
+ doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+ }
when(mMockRunner.asBinder()).thenReturn(new Binder());
mController = new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks,
DEFAULT_DISPLAY);
@@ -88,7 +98,7 @@
// Verify that the finish callback to reparent the leash is called
verify(mFinishedCallback).onAnimationFinished(eq(adapter));
// Verify the animation canceled callback to the app was made
- verify(mMockRunner).onAnimationCanceled();
+ verify(mMockRunner).onAnimationCanceled(false);
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
}
@@ -131,6 +141,31 @@
assertFalse(mController.isAnimatingTask(hiddenAppWindow.getTask()));
}
+ @Test
+ public void testCancelAnimationWithScreenShot() throws Exception {
+ mWm.setRecentsAnimationController(mController);
+ final AppWindowToken appWindow = createAppWindowToken(mDisplayContent,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowState win1 = createWindow(null, TYPE_BASE_APPLICATION, appWindow, "win1");
+ appWindow.addWindow(win1);
+ assertEquals(appWindow.getTask().getTopVisibleAppToken(), appWindow);
+ assertEquals(appWindow.findMainWindow(), win1);
+
+ mController.addAnimation(appWindow.getTask(), false /* isRecentTaskInvisible */);
+ assertTrue(mController.isAnimatingTask(appWindow.getTask()));
+
+ mController.setCancelWithDeferredScreenshotLocked(true);
+ mController.cancelAnimationWithScreenShot();
+ verify(mMockRunner).onAnimationCanceled(true /* deferredWithScreenshot */);
+ assertNotNull(mController.mRecentScreenshotAnimator);
+ assertTrue(mController.mRecentScreenshotAnimator.isAnimating());
+
+ // Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
+ // animation.
+ mController.mRecentScreenshotAnimator.cancelAnimation();
+ verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true);
+ }
+
private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
verify(binder, atLeast(0)).asBinder();
verifyNoMoreInteractions(binder);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 5f3a290..5625ea4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -20,7 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
@@ -29,6 +28,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
+import static org.mockito.ArgumentMatchers.any;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -51,11 +52,15 @@
private Context mContext = InstrumentationRegistry.getContext();
private ComponentName mRecentsComponent;
+ private RecentsAnimationController mRecentsAnimationController;
@Before
public void setUp() throws Exception {
mRecentsComponent = new ComponentName(mContext.getPackageName(), "RecentsActivity");
mService = new TestActivityTaskManagerService(mContext);
+ mRecentsAnimationController = mock(RecentsAnimationController.class);
+ doReturn(mRecentsAnimationController).when(
+ mService.mWindowManager).getRecentsAnimationController();
final RecentTasks recentTasks = mService.getRecentTasks();
spyOn(recentTasks);
@@ -96,9 +101,18 @@
fullscreenStack.moveToFront("Activity start");
- // Ensure that the recents animation was canceled
+ // Ensure that the recents animation was canceled by cancelAnimationSynchronously().
verify(mService.mWindowManager, times(1)).cancelRecentsAnimationSynchronously(
eq(REORDER_KEEP_IN_PLACE), any());
+
+ // Assume recents animation already started, set a state that cancel recents animation
+ // with screenshot.
+ doReturn(true).when(mRecentsAnimationController).shouldCancelWithDeferredScreenshot();
+ // Start another fullscreen activity.
+ fullscreenStack2.moveToFront("Activity start");
+
+ // Ensure that the recents animation was canceled by cancelOnNextTransitionStart().
+ verify(mRecentsAnimationController, times(1)).cancelOnNextTransitionStart();
}
@Test
@@ -137,5 +151,6 @@
// Ensure that the recents animation was NOT canceled
verify(mService.mWindowManager, times(0)).cancelRecentsAnimationSynchronously(
eq(REORDER_KEEP_IN_PLACE), any());
+ verify(mRecentsAnimationController, times(0)).cancelOnNextTransitionStart();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 45fe5d2..35a8ec3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -20,9 +20,11 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.app.WindowConfiguration;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -71,5 +73,21 @@
assertFalse(app.isVisible());
assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
}
+
+ @Test
+ public void testUpdateDefaultDisplayWindowingModeOnSettingsRetrieved() {
+ synchronized (mWm.mGlobalLock) {
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FULLSCREEN,
+ mWm.getDefaultDisplayContentLocked().getWindowingMode());
+
+ mWm.mIsPc = true;
+ mWm.mSupportsFreeformWindowManagement = true;
+
+ mWm.mRoot.onSettingsRetrieved();
+
+ assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
+ mWm.getDefaultDisplayContentLocked().getWindowingMode());
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 1b396f5..00e479fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -32,7 +32,6 @@
import android.platform.test.annotations.Presubmit;
import android.view.InputChannel;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -89,7 +88,6 @@
assertNull(mTarget.getDragWindowHandleLocked());
}
- @FlakyTest(bugId = 69229402)
@Test
public void testHandleTapOutsideTask() {
synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index b9e9909..d8a01b9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -159,7 +159,6 @@
* Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
*/
@Test
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index b03f63b..4f8fe5b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -87,7 +87,6 @@
*/
@SmallTest
@Presubmit
-@FlakyTest(bugId = 124127512)
public class WindowStateTests extends WindowTestsBase {
private static int sPreviousNewInsetsMode;
@@ -363,7 +362,6 @@
assertFalse(app.canAffectSystemUiFlags());
}
- @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
@Test
public void testVisibleWithInsetsProvider() throws Exception {
final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2fc6efa..7d7c3985 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -43,7 +43,6 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.After;
@@ -212,7 +211,6 @@
return createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, name);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithNoTarget() {
mDisplayContent.mInputMethodTarget = null;
@@ -230,7 +228,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -250,7 +247,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
@@ -277,7 +273,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
@@ -301,7 +296,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
@@ -329,7 +323,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testAssignWindowLayers_ForStatusBarImeTarget() {
mDisplayContent.mInputMethodTarget = mStatusBarWindow;
@@ -344,7 +337,6 @@
assertWindowHigher(mImeDialogWindow, mImeWindow);
}
- @FlakyTest(bugId = 124088319)
@Test
public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
@@ -432,7 +424,6 @@
}
}
- @FlakyTest(bugId = 124088319)
@Test
public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index f5b4308..92ea872 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -22,7 +22,6 @@
],
shared_libs: [
"libbase",
- "libz",
"slicer",
],
static_libs: [
diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java
index 4e74395..6b9b83d 100644
--- a/telecomm/java/android/telecom/AudioState.java
+++ b/telecomm/java/android/telecom/AudioState.java
@@ -18,6 +18,7 @@
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -54,11 +55,11 @@
private static final int ROUTE_ALL = ROUTE_EARPIECE | ROUTE_BLUETOOTH | ROUTE_WIRED_HEADSET |
ROUTE_SPEAKER;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
private final boolean isMuted;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
private final int route;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
private final int supportedRouteMask;
public AudioState(boolean muted, int route, int supportedRouteMask) {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index dcaa499..c05a346 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -144,6 +144,16 @@
public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS =
"android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
+
+ /**
+ * Extra key used to indicate whether a {@link CallScreeningService} has requested to silence
+ * the ringtone for a call. If the {@link InCallService} declares
+ * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in its manifest, it should not
+ * play a ringtone for an incoming call with this extra key set.
+ */
+ public static final String EXTRA_SILENT_RINGING_REQUESTED =
+ "android.telecom.extra.SILENT_RINGING_REQUESTED";
+
/**
* Call event sent from a {@link Call} via {@link #sendCallEvent(String, Bundle)} to inform
* Telecom that the user has requested that the current {@link Call} should be handed over
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index d521e30..d01c889 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -17,6 +17,7 @@
package android.telecom;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.app.Service;
import android.content.Intent;
@@ -206,12 +207,12 @@
}
@Override
- public final IBinder onBind(Intent intent) {
+ public final @Nullable IBinder onBind(@NonNull Intent intent) {
return new CallRedirectionBinder();
}
@Override
- public final boolean onUnbind(Intent intent) {
+ public final boolean onUnbind(@NonNull Intent intent) {
return false;
}
}
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 2fa388f..b1aece7 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -259,12 +259,14 @@
public static class CallResponse {
private final boolean mShouldDisallowCall;
private final boolean mShouldRejectCall;
+ private final boolean mShouldSilenceCall;
private final boolean mShouldSkipCallLog;
private final boolean mShouldSkipNotification;
private CallResponse(
boolean shouldDisallowCall,
boolean shouldRejectCall,
+ boolean shouldSilenceCall,
boolean shouldSkipCallLog,
boolean shouldSkipNotification) {
if (!shouldDisallowCall
@@ -276,6 +278,7 @@
mShouldRejectCall = shouldRejectCall;
mShouldSkipCallLog = shouldSkipCallLog;
mShouldSkipNotification = shouldSkipNotification;
+ mShouldSilenceCall = shouldSilenceCall;
}
/*
@@ -294,6 +297,13 @@
}
/*
+ * @return Whether the ringtone should be silenced for the incoming call.
+ */
+ public boolean getSilenceCall() {
+ return mShouldSilenceCall;
+ }
+
+ /*
* @return Whether the incoming call should not be displayed in the call log.
*/
public boolean getSkipCallLog() {
@@ -310,6 +320,7 @@
public static class Builder {
private boolean mShouldDisallowCall;
private boolean mShouldRejectCall;
+ private boolean mShouldSilenceCall;
private boolean mShouldSkipCallLog;
private boolean mShouldSkipNotification;
@@ -331,6 +342,21 @@
}
/**
+ * Sets whether ringing should be silenced for the incoming call. When set
+ * to {@code true}, the Telecom framework will not play a ringtone for the call.
+ * The call will, however, still be sent to the default dialer app if it is not blocked.
+ * A {@link CallScreeningService} can use this to ensure a potential nuisance call is
+ * still surfaced to the user, but in a less intrusive manner.
+ *
+ * Setting this to true only makes sense when the call has not been disallowed
+ * using {@link #setDisallowCall(boolean)}.
+ */
+ public @NonNull Builder setSilenceCall(boolean shouldSilenceCall) {
+ mShouldSilenceCall = shouldSilenceCall;
+ return this;
+ }
+
+ /**
* Sets whether the incoming call should not be displayed in the call log. This property
* should only be set to true if the call is disallowed.
* <p>
@@ -356,6 +382,7 @@
return new CallResponse(
mShouldDisallowCall,
mShouldRejectCall,
+ mShouldSilenceCall,
mShouldSkipCallLog,
mShouldSkipNotification);
}
@@ -411,10 +438,11 @@
public abstract void onScreenCall(@NonNull Call.Details callDetails);
/**
- * Responds to the given incoming call, either allowing it or disallowing it.
+ * Responds to the given incoming call, either allowing it, silencing it or disallowing it.
* <p>
* The {@link CallScreeningService} calls this method to inform the system whether the call
- * should be silently blocked or not.
+ * should be silently blocked or not. In the event that it should not be blocked, it may
+ * also be requested to ring silently.
* <p>
* Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
* {@link Call.Details#DIRECTION_INCOMING}.
@@ -436,6 +464,8 @@
!response.getSkipCallLog(),
!response.getSkipNotification(),
new ComponentName(getPackageName(), getClass().getName()));
+ } else if (response.getSilenceCall()) {
+ mCallScreeningAdapter.silenceCall(callDetails.getTelecomCallId());
} else {
mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId());
}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index d3ccd2c..0cc052e 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -19,6 +19,7 @@
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.bluetooth.BluetoothDevice;
+import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -328,10 +329,12 @@
* become active, and the touch screen and display will be turned off when the user's face
* is detected to be in close proximity to the screen. This operation is a no-op on devices
* that do not have a proximity sensor.
- *
+ * <p>
+ * This API does not actually turn on the proximity sensor; apps should do this on their own if
+ * required.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
public final void setProximitySensorOn() {
mInCallAdapter.turnProximitySensorOn();
}
@@ -344,10 +347,12 @@
* @param screenOnImmediately If true, the screen will be turned on immediately if it was
* previously off. Otherwise, the screen will only be turned on after the proximity sensor
* is no longer triggered.
- *
+ * <p>
+ * This API does not actually turn of the proximity sensor; apps should do this on their own if
+ * required.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
public final void setProximitySensorOff(boolean screenOnImmediately) {
mInCallAdapter.turnProximitySensorOff(screenOnImmediately);
}
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index a84ce55..71a28b5 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -42,7 +42,7 @@
* See {@link PhoneAccount}, {@link TelecomManager}.
*/
public final class PhoneAccountHandle implements Parcelable {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
private final ComponentName mComponentName;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mId;
diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java
index 2c7fecb..cb74012 100644
--- a/telecomm/java/android/telecom/VideoCallImpl.java
+++ b/telecomm/java/android/telecom/VideoCallImpl.java
@@ -18,6 +18,7 @@
import android.annotation.UnsupportedAppUsage;
import android.net.Uri;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -218,7 +219,7 @@
mTargetSdkVersion = sdkVersion;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
public void destroy() {
unregisterCallback(mCallback);
}
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index a86c830..1160d27 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -29,6 +29,8 @@
oneway interface ICallScreeningAdapter {
void allowCall(String callId);
+ void silenceCall(String callId);
+
void disallowCall(
String callId,
boolean shouldReject,
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 75165af..81553a3 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -16,13 +16,59 @@
package android.telephony;
+import android.annotation.IntDef;
import android.annotation.SystemApi;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Contains access network related constants.
*/
public final class AccessNetworkConstants {
+ /**
+ * Wireless transportation type
+ *
+ * @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"TRANSPORT_TYPE_"},
+ value = {
+ TRANSPORT_TYPE_INVALID,
+ TRANSPORT_TYPE_WWAN,
+ TRANSPORT_TYPE_WLAN})
+ public @interface TransportType {}
+
+ /**
+ * Invalid transport type
+ * @hide
+ */
+ @SystemApi
+ public static final int TRANSPORT_TYPE_INVALID = -1;
+
+ /**
+ * Transport type for Wireless Wide Area Networks (i.e. Cellular)
+ * @hide
+ */
+ @SystemApi
+ public static final int TRANSPORT_TYPE_WWAN = 1;
+
+ /**
+ * Transport type for Wireless Local Area Networks (i.e. Wifi)
+ * @hide
+ */
+ @SystemApi
+ public static final int TRANSPORT_TYPE_WLAN = 2;
+
+ /** @hide */
+ public static String transportTypeToString(@TransportType int transportType) {
+ switch (transportType) {
+ case TRANSPORT_TYPE_WWAN: return "WWAN";
+ case TRANSPORT_TYPE_WLAN: return "WLAN";
+ default: return Integer.toString(transportType);
+ }
+ }
+
public static final class AccessNetworkType {
public static final int UNKNOWN = 0;
public static final int GERAN = 1;
@@ -49,39 +95,7 @@
}
/**
- * Wireless transportation type
- * @hide
- */
- @SystemApi
- public static final class TransportType {
- /**
- * Invalid transport type.
- * @hide
- */
- public static final int INVALID = -1;
-
- /** Wireless Wide Area Networks (i.e. Cellular) */
- public static final int WWAN = 1;
-
- /** Wireless Local Area Networks (i.e. Wifi) */
- public static final int WLAN = 2;
-
- /** @hide */
- private TransportType() {}
-
- /** @hide */
- public static String toString(int type) {
- switch (type) {
- case INVALID: return "INVALID";
- case WWAN: return "WWAN";
- case WLAN: return "WLAN";
- default: return Integer.toString(type);
- }
- }
- }
-
- /**
- * Frenquency bands for GERAN.
+ * Frequency bands for GERAN.
* http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf
*/
public static final class GeranBand {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 524d080..5f9ef3c 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1520,6 +1520,14 @@
"carrier_app_no_wake_signal_config";
/**
+ * Determines whether the carrier app needed to be involved when users try to finish setting up
+ * the SIM card to get network service.
+ * @hide
+ */
+ public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL =
+ "carrier_app_required_during_setup_bool";
+
+ /**
* Default value for {@link Settings.Global#DATA_ROAMING}
* @hide
*/
@@ -2307,9 +2315,9 @@
"undelivered_sms_message_expiration_time";
/**
- * Specifies a carrier-defined {@link CallRedirectionService} which Telecom will bind
- * to for outgoing calls. An empty string indicates that no carrier-defined
- * {@link CallRedirectionService} is specified.
+ * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom
+ * will bind to for outgoing calls. An empty string indicates that no carrier-defined
+ * {@link android.telecom.CallRedirectionService} is specified.
* @hide
*/
public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING =
@@ -2867,6 +2875,7 @@
sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
sDefaults.putString(KEY_SIM_COUNTRY_ISO_OVERRIDE_STRING, "");
sDefaults.putString(KEY_CARRIER_CALL_SCREENING_APP_STRING, "");
+ sDefaults.putString(KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING, null);
sDefaults.putBoolean(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_OVERRIDE_BOOL, false);
sDefaults.putString(KEY_CDMA_HOME_REGISTERED_PLMN_NAME_STRING, "");
sDefaults.putBoolean(KEY_SUPPORT_DIRECT_FDN_DIALING_BOOL, false);
@@ -2922,6 +2931,7 @@
+ "com.android.internal.telephony.CARRIER_SIGNAL_RESET"
});
sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
+ sDefaults.putBoolean(KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL, false);
// Default carrier app configurations
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index f0a26f5..ca264f7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -318,8 +318,8 @@
public static final int LOW_POWER_MODE_OR_POWERING_DOWN = 0x7FC;
/** APN has been disabled. */
public static final int APN_DISABLED = 0x7FD;
- /** PPP inactivity timer expired. */
- public static final int PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
+ /** Maximum PPP inactivity timer expired. */
+ public static final int MAX_PPP_INACTIVITY_TIMER_EXPIRED = 0x7FE;
/** IPv6 address transfer failed. */
public static final int IPV6_ADDRESS_TRANSFER_FAILED = 0x7FF;
/** Target RAT swap failed. */
@@ -339,12 +339,12 @@
* IPv4 data call bring up is rejected because the UE already maintains the allotted maximum
* number of IPv4 data connections.
*/
- public static final int IPV4_CONNECTIONS_LIMIT_REACHED = 0x804;
+ public static final int MAX_IPV4_CONNECTIONS = 0x804;
/**
* IPv6 data call bring up is rejected because the UE already maintains the allotted maximum
* number of IPv6 data connections.
*/
- public static final int IPV6_CONNECTIONS_LIMIT_REACHED = 0x805;
+ public static final int MAX_IPV6_CONNECTIONS = 0x805;
/**
* New PDN bring up is rejected during interface selection because the UE has already allotted
* the available interfaces for other PDNs.
@@ -416,7 +416,7 @@
*/
public static final int CHANNEL_ACQUISITION_FAILURE = 0x81E;
/** Maximum access probes transmitted. */
- public static final int ACCESS_PROBE_LIMIT_REACHED = 0x81F;
+ public static final int MAX_ACCESS_PROBE = 0x81F;
/** Concurrent service is not supported by base station. */
public static final int CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION = 0x820;
/** There was no response received from the base station. */
@@ -1079,14 +1079,14 @@
SIM_CARD_CHANGED,
LOW_POWER_MODE_OR_POWERING_DOWN,
APN_DISABLED,
- PPP_INACTIVITY_TIMER_EXPIRED,
+ MAX_PPP_INACTIVITY_TIMER_EXPIRED,
IPV6_ADDRESS_TRANSFER_FAILED,
TRAT_SWAP_FAILED,
EHRPD_TO_HRPD_FALLBACK,
MIP_CONFIG_FAILURE,
PDN_INACTIVITY_TIMER_EXPIRED,
- IPV4_CONNECTIONS_LIMIT_REACHED,
- IPV6_CONNECTIONS_LIMIT_REACHED,
+ MAX_IPV4_CONNECTIONS,
+ MAX_IPV6_CONNECTIONS,
APN_MISMATCH,
IP_VERSION_MISMATCH,
DUN_CALL_DISALLOWED,
@@ -1112,7 +1112,7 @@
CDMA_INCOMING_CALL,
CDMA_ALERT_STOP,
CHANNEL_ACQUISITION_FAILURE,
- ACCESS_PROBE_LIMIT_REACHED,
+ MAX_ACCESS_PROBE,
CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
NO_RESPONSE_FROM_BASE_STATION,
REJECTED_BY_BASE_STATION,
@@ -1447,14 +1447,14 @@
sFailCauseMap.put(SIM_CARD_CHANGED, "SIM_CARD_CHANGED");
sFailCauseMap.put(LOW_POWER_MODE_OR_POWERING_DOWN, "LOW_POWER_MODE_OR_POWERING_DOWN");
sFailCauseMap.put(APN_DISABLED, "APN_DISABLED");
- sFailCauseMap.put(PPP_INACTIVITY_TIMER_EXPIRED, "PPP_INACTIVITY_TIMER_EXPIRED");
+ sFailCauseMap.put(MAX_PPP_INACTIVITY_TIMER_EXPIRED, "MAX_PPP_INACTIVITY_TIMER_EXPIRED");
sFailCauseMap.put(IPV6_ADDRESS_TRANSFER_FAILED, "IPV6_ADDRESS_TRANSFER_FAILED");
sFailCauseMap.put(TRAT_SWAP_FAILED, "TRAT_SWAP_FAILED");
sFailCauseMap.put(EHRPD_TO_HRPD_FALLBACK, "EHRPD_TO_HRPD_FALLBACK");
sFailCauseMap.put(MIP_CONFIG_FAILURE, "MIP_CONFIG_FAILURE");
sFailCauseMap.put(PDN_INACTIVITY_TIMER_EXPIRED, "PDN_INACTIVITY_TIMER_EXPIRED");
- sFailCauseMap.put(IPV4_CONNECTIONS_LIMIT_REACHED, "IPV4_CONNECTIONS_LIMIT_REACHED");
- sFailCauseMap.put(IPV6_CONNECTIONS_LIMIT_REACHED, "IPV6_CONNECTIONS_LIMIT_REACHED");
+ sFailCauseMap.put(MAX_IPV4_CONNECTIONS, "MAX_IPV4_CONNECTIONS");
+ sFailCauseMap.put(MAX_IPV6_CONNECTIONS, "MAX_IPV6_CONNECTIONS");
sFailCauseMap.put(APN_MISMATCH, "APN_MISMATCH");
sFailCauseMap.put(IP_VERSION_MISMATCH, "IP_VERSION_MISMATCH");
sFailCauseMap.put(DUN_CALL_DISALLOWED, "DUN_CALL_DISALLOWED");
@@ -1480,7 +1480,7 @@
sFailCauseMap.put(CDMA_INCOMING_CALL, "CDMA_INCOMING_CALL");
sFailCauseMap.put(CDMA_ALERT_STOP, "CDMA_ALERT_STOP");
sFailCauseMap.put(CHANNEL_ACQUISITION_FAILURE, "CHANNEL_ACQUISITION_FAILURE");
- sFailCauseMap.put(ACCESS_PROBE_LIMIT_REACHED, "ACCESS_PROBE_LIMIT_REACHED");
+ sFailCauseMap.put(MAX_ACCESS_PROBE, "MAX_ACCESS_PROBE");
sFailCauseMap.put(CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION,
"CONCURRENT_SERVICE_NOT_SUPPORTED_BY_BASE_STATION");
sFailCauseMap.put(NO_RESPONSE_FROM_BASE_STATION, "NO_RESPONSE_FROM_BASE_STATION");
diff --git a/telephony/java/android/telephony/INetworkService.aidl b/telephony/java/android/telephony/INetworkService.aidl
index 9ef7186..67e5650 100644
--- a/telephony/java/android/telephony/INetworkService.aidl
+++ b/telephony/java/android/telephony/INetworkService.aidl
@@ -25,7 +25,7 @@
{
void createNetworkServiceProvider(int slotId);
void removeNetworkServiceProvider(int slotId);
- void getNetworkRegistrationState(int slotId, int domain, INetworkServiceCallback callback);
- void registerForNetworkRegistrationStateChanged(int slotId, INetworkServiceCallback callback);
- void unregisterForNetworkRegistrationStateChanged(int slotId, INetworkServiceCallback callback);
+ void getNetworkRegistrationInfo(int slotId, int domain, INetworkServiceCallback callback);
+ void registerForNetworkRegistrationInfoChanged(int slotId, INetworkServiceCallback callback);
+ void unregisterForNetworkRegistrationInfoChanged(int slotId, INetworkServiceCallback callback);
}
diff --git a/telephony/java/android/telephony/INetworkServiceCallback.aidl b/telephony/java/android/telephony/INetworkServiceCallback.aidl
index 520598f..33b3ac0 100644
--- a/telephony/java/android/telephony/INetworkServiceCallback.aidl
+++ b/telephony/java/android/telephony/INetworkServiceCallback.aidl
@@ -16,7 +16,7 @@
package android.telephony;
-import android.telephony.NetworkRegistrationState;
+import android.telephony.NetworkRegistrationInfo;
/**
* Network service call back interface
@@ -24,6 +24,6 @@
*/
oneway interface INetworkServiceCallback
{
- void onGetNetworkRegistrationStateComplete(int result, in NetworkRegistrationState state);
+ void onGetNetworkRegistrationInfoComplete(int result, in NetworkRegistrationInfo state);
void onNetworkStateChanged();
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.aidl b/telephony/java/android/telephony/NetworkRegistrationInfo.aidl
similarity index 94%
rename from telephony/java/android/telephony/NetworkRegistrationState.aidl
rename to telephony/java/android/telephony/NetworkRegistrationInfo.aidl
index 98cba77..5c803bf 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.aidl
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.aidl
@@ -16,4 +16,4 @@
package android.telephony;
-parcelable NetworkRegistrationState;
+parcelable NetworkRegistrationInfo;
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
similarity index 60%
rename from telephony/java/android/telephony/NetworkRegistrationState.java
rename to telephony/java/android/telephony/NetworkRegistrationInfo.java
index a6c81db..9145b25 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -27,16 +27,18 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
- * Description of a mobile network registration state
+ * Description of a mobile network registration info
* @hide
*/
@SystemApi
-public class NetworkRegistrationState implements Parcelable {
+public final class NetworkRegistrationInfo implements Parcelable {
/**
* Network domain
* @hide
@@ -51,41 +53,42 @@
public static final int DOMAIN_PS = 2;
/**
- * Registration state
+ * Network registration state
* @hide
*/
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "REG_STATE_",
- value = {REG_STATE_NOT_REG_NOT_SEARCHING, REG_STATE_HOME, REG_STATE_NOT_REG_SEARCHING,
- REG_STATE_DENIED, REG_STATE_UNKNOWN, REG_STATE_ROAMING})
- public @interface RegState {}
+ @IntDef(prefix = "REGISTRATION_STATE_",
+ value = {REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING, REGISTRATION_STATE_HOME,
+ REGISTRATION_STATE_NOT_REGISTERED_SEARCHING, REGISTRATION_STATE_DENIED,
+ REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING})
+ public @interface RegistrationState {}
- /** Not registered. The device is not currently searching a new operator to register */
- public static final int REG_STATE_NOT_REG_NOT_SEARCHING = 0;
- /** Registered on home network */
- public static final int REG_STATE_HOME = 1;
- /** Not registered. The device is currently searching a new operator to register */
- public static final int REG_STATE_NOT_REG_SEARCHING = 2;
- /** Registration denied */
- public static final int REG_STATE_DENIED = 3;
- /** Registration state is unknown */
- public static final int REG_STATE_UNKNOWN = 4;
- /** Registered on roaming network */
- public static final int REG_STATE_ROAMING = 5;
+ /** Not registered. The device is not currently searching a new operator to register. */
+ public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0;
+ /** Registered on home network. */
+ public static final int REGISTRATION_STATE_HOME = 1;
+ /** Not registered. The device is currently searching a new operator to register. */
+ public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2;
+ /** Registration denied. */
+ public static final int REGISTRATION_STATE_DENIED = 3;
+ /** Registration state is unknown. */
+ public static final int REGISTRATION_STATE_UNKNOWN = 4;
+ /** Registered on roaming network. */
+ public static final int REGISTRATION_STATE_ROAMING = 5;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = "NR_STATUS_",
- value = {NR_STATUS_NONE, NR_STATUS_RESTRICTED, NR_STATUS_NOT_RESTRICTED,
- NR_STATUS_CONNECTED})
- public @interface NRStatus {}
+ @IntDef(prefix = "NR_STATE_",
+ value = {NR_STATE_NONE, NR_STATE_RESTRICTED, NR_STATE_NOT_RESTRICTED,
+ NR_STATE_CONNECTED})
+ public @interface NRState {}
/**
* The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR
* Dual Connectivity(EN-DC).
* @hide
*/
- public static final int NR_STATUS_NONE = -1;
+ public static final int NR_STATE_NONE = -1;
/**
* The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but
@@ -93,7 +96,7 @@
* the selected PLMN.
* @hide
*/
- public static final int NR_STATUS_RESTRICTED = 1;
+ public static final int NR_STATE_RESTRICTED = 1;
/**
* The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both
@@ -101,14 +104,14 @@
* selected PLMN.
* @hide
*/
- public static final int NR_STATUS_NOT_RESTRICTED = 2;
+ public static final int NR_STATE_NOT_RESTRICTED = 2;
/**
* The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and
* also connected to at least one 5G cell as a secondary serving cell.
* @hide
*/
- public static final int NR_STATUS_CONNECTED = 3;
+ public static final int NR_STATE_CONNECTED = 3;
/**
* Supported service type
@@ -116,24 +119,36 @@
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "SERVICE_TYPE_",
- value = {SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS, SERVICE_TYPE_VIDEO,
- SERVICE_TYPE_EMERGENCY})
+ value = {SERVICE_TYPE_UNKNOWN, SERVICE_TYPE_VOICE, SERVICE_TYPE_DATA, SERVICE_TYPE_SMS,
+ SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY})
public @interface ServiceType {}
+ /** Unkown service */
+ public static final int SERVICE_TYPE_UNKNOWN = 0;
+
+ /** Voice service */
public static final int SERVICE_TYPE_VOICE = 1;
+
+ /** Data service */
public static final int SERVICE_TYPE_DATA = 2;
+
+ /** SMS service */
public static final int SERVICE_TYPE_SMS = 3;
+
+ /** Video service */
public static final int SERVICE_TYPE_VIDEO = 4;
+
+ /** Emergency service */
public static final int SERVICE_TYPE_EMERGENCY = 5;
@Domain
private final int mDomain;
- /** {@link TransportType} */
+ @TransportType
private final int mTransportType;
- @RegState
- private final int mRegState;
+ @RegistrationState
+ private final int mRegistrationState;
/**
* Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
@@ -145,15 +160,15 @@
@NetworkType
private int mAccessNetworkTechnology;
- @NRStatus
- private int mNrStatus;
+ @NRState
+ private int mNrState;
private final int mRejectCause;
private final boolean mEmergencyOnly;
@ServiceType
- private final int[] mAvailableServices;
+ private final ArrayList<Integer> mAvailableServices;
@Nullable
private CellIdentity mCellIdentity;
@@ -165,96 +180,106 @@
private DataSpecificRegistrationStates mDataSpecificStates;
/**
- * @param domain Network domain. Must be a {@link Domain}. For {@link TransportType#WLAN}
- * transport, this must set to {@link #DOMAIN_PS}.
- * @param transportType Transport type. Must be one of the{@link TransportType}.
- * @param regState Network registration state. Must be one of the {@link RegState}. For
- * {@link TransportType#WLAN} transport, only {@link #REG_STATE_HOME} and
- * {@link #REG_STATE_NOT_REG_NOT_SEARCHING} are valid states.
- * @param accessNetworkTechnology Access network technology.For {@link TransportType#WLAN}
- * transport, set to {@link TelephonyManager#NETWORK_TYPE_IWLAN}.
- * @param rejectCause Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
- * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
- * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA. If
- * the reject cause is not supported or unknown, set it to 0.
+ * @param domain Network domain. Must be a {@link Domain}. For transport type
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, this must set to {@link #DOMAIN_PS}.
+ * @param transportType Transport type.
+ * @param registrationState Network registration state. For transport type
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, only
+ * {@link #REGISTRATION_STATE_HOME} and {@link #REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING}
+ * are valid states.
+ * @param accessNetworkTechnology Access network technology.For transport type
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, set to
+ * {@link TelephonyManager#NETWORK_TYPE_IWLAN}.
+ * @param rejectCause Reason for denial if the registration state is
+ * {@link #REGISTRATION_STATE_DENIED}. Depending on {@code accessNetworkTechnology}, the values
+ * are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2
+ * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0.
* // TODO: Add IWLAN reject cause reference
* @param emergencyOnly True if this registration is for emergency only.
- * @param availableServices The list of the supported services. Each element must be one of
- * the {@link ServiceType}.
+ * @param availableServices The list of the supported services.
* @param cellIdentity The identity representing a unique cell or wifi AP. Set to null if the
* information is not available.
*/
- public NetworkRegistrationState(@Domain int domain, int transportType, @RegState int regState,
- @NetworkType int accessNetworkTechnology, int rejectCause,
- boolean emergencyOnly,
- @NonNull @ServiceType int[] availableServices,
- @Nullable CellIdentity cellIdentity) {
+ private NetworkRegistrationInfo(@Domain int domain, @TransportType int transportType,
+ @RegistrationState int registrationState,
+ @NetworkType int accessNetworkTechnology, int rejectCause,
+ boolean emergencyOnly,
+ @Nullable @ServiceType List<Integer> availableServices,
+ @Nullable CellIdentity cellIdentity) {
mDomain = domain;
mTransportType = transportType;
- mRegState = regState;
- mRoamingType = (regState == REG_STATE_ROAMING)
+ mRegistrationState = registrationState;
+ mRoamingType = (registrationState == REGISTRATION_STATE_ROAMING)
? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
mAccessNetworkTechnology = accessNetworkTechnology;
mRejectCause = rejectCause;
- mAvailableServices = availableServices;
+ mAvailableServices = (availableServices != null)
+ ? new ArrayList<>(availableServices) : new ArrayList<>();
mCellIdentity = cellIdentity;
mEmergencyOnly = emergencyOnly;
- mNrStatus = NR_STATUS_NONE;
+ mNrState = NR_STATE_NONE;
}
/**
- * Constructor for voice network registration states.
+ * Constructor for voice network registration info.
* @hide
*/
- public NetworkRegistrationState(int domain, int transportType, int regState,
- int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
- int[] availableServices, @Nullable CellIdentity cellIdentity, boolean cssSupported,
- int roamingIndicator, int systemIsInPrl, int defaultRoamingIndicator) {
- this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
- availableServices, cellIdentity);
+ public NetworkRegistrationInfo(int domain, @TransportType int transportType,
+ int registrationState, int accessNetworkTechnology,
+ int rejectCause, boolean emergencyOnly,
+ @Nullable List<Integer> availableServices,
+ @Nullable CellIdentity cellIdentity, boolean cssSupported,
+ int roamingIndicator, int systemIsInPrl,
+ int defaultRoamingIndicator) {
+ this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
+ emergencyOnly, availableServices, cellIdentity);
mVoiceSpecificStates = new VoiceSpecificRegistrationStates(cssSupported, roamingIndicator,
systemIsInPrl, defaultRoamingIndicator);
}
/**
- * Constructor for data network registration states.
+ * Constructor for data network registration info.
* @hide
*/
- public NetworkRegistrationState(int domain, int transportType, int regState,
- int accessNetworkTechnology, int rejectCause, boolean emergencyOnly,
- int[] availableServices, @Nullable CellIdentity cellIdentity, int maxDataCalls,
- boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable,
- LteVopsSupportInfo lteVopsSupportInfo) {
- this(domain, transportType, regState, accessNetworkTechnology, rejectCause, emergencyOnly,
- availableServices, cellIdentity);
+ public NetworkRegistrationInfo(int domain, @TransportType int transportType,
+ int registrationState, int accessNetworkTechnology,
+ int rejectCause, boolean emergencyOnly,
+ @Nullable List<Integer> availableServices,
+ @Nullable CellIdentity cellIdentity, int maxDataCalls,
+ boolean isDcNrRestricted, boolean isNrAvailable,
+ boolean isEndcAvailable,
+ LteVopsSupportInfo lteVopsSupportInfo) {
+ this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
+ emergencyOnly, availableServices, cellIdentity);
mDataSpecificStates = new DataSpecificRegistrationStates(
maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
- updateNrStatus(mDataSpecificStates);
+ updateNrState(mDataSpecificStates);
}
- private NetworkRegistrationState(Parcel source) {
+ private NetworkRegistrationInfo(Parcel source) {
mDomain = source.readInt();
mTransportType = source.readInt();
- mRegState = source.readInt();
+ mRegistrationState = source.readInt();
mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
mEmergencyOnly = source.readBoolean();
- mAvailableServices = source.createIntArray();
+ mAvailableServices = new ArrayList<>();
+ source.readList(mAvailableServices, Integer.class.getClassLoader());
mCellIdentity = source.readParcelable(CellIdentity.class.getClassLoader());
mVoiceSpecificStates = source.readParcelable(
VoiceSpecificRegistrationStates.class.getClassLoader());
mDataSpecificStates = source.readParcelable(
DataSpecificRegistrationStates.class.getClassLoader());
- mNrStatus = source.readInt();
+ mNrState = source.readInt();
}
/**
* @return The transport type.
*/
- public int getTransportType() { return mTransportType; }
+ public @TransportType int getTransportType() { return mTransportType; }
/**
* @return The network domain.
@@ -262,23 +287,23 @@
public @Domain int getDomain() { return mDomain; }
/**
- * @return the 5G NR connection status.
+ * @return the 5G NR connection state.
* @hide
*/
- public @NRStatus int getNrStatus() {
- return mNrStatus;
+ public @NRState int getNrState() {
+ return mNrState;
}
/** @hide */
- public void setNrStatus(@NRStatus int nrStatus) {
- mNrStatus = nrStatus;
+ public void setNrState(@NRState int nrState) {
+ mNrState = nrState;
}
/**
* @return The registration state.
*/
- public @RegState int getRegState() {
- return mRegState;
+ public @RegistrationState int getRegistrationState() {
+ return mRegistrationState;
}
/**
@@ -293,7 +318,8 @@
* @return {@code true} if in service.
*/
public boolean isInService() {
- return mRegState == REG_STATE_HOME || mRegState == REG_STATE_ROAMING;
+ return mRegistrationState == REGISTRATION_STATE_HOME
+ || mRegistrationState == REGISTRATION_STATE_ROAMING;
}
/**
@@ -323,7 +349,9 @@
*/
@NonNull
@ServiceType
- public int[] getAvailableServices() { return mAvailableServices; }
+ public List<Integer> getAvailableServices() {
+ return Collections.unmodifiableList(mAvailableServices);
+ }
/**
* @return The access network technology {@link NetworkType}.
@@ -341,7 +369,7 @@
}
/**
- * @return Reason for denial if the registration state is {@link #REG_STATE_DENIED}.
+ * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}.
* Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008
* 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA
*/
@@ -402,28 +430,28 @@
*
* @hide
*
- * @param regState The registration state
+ * @param registrationState The registration state
* @return The reg state in string
*/
- public static String regStateToString(@RegState int regState) {
- switch (regState) {
- case REG_STATE_NOT_REG_NOT_SEARCHING: return "NOT_REG_NOT_SEARCHING";
- case REG_STATE_HOME: return "HOME";
- case REG_STATE_NOT_REG_SEARCHING: return "NOT_REG_SEARCHING";
- case REG_STATE_DENIED: return "DENIED";
- case REG_STATE_UNKNOWN: return "UNKNOWN";
- case REG_STATE_ROAMING: return "ROAMING";
+ public static String registrationStateToString(@RegistrationState int registrationState) {
+ switch (registrationState) {
+ case REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING: return "NOT_REG_OR_SEARCHING";
+ case REGISTRATION_STATE_HOME: return "HOME";
+ case REGISTRATION_STATE_NOT_REGISTERED_SEARCHING: return "NOT_REG_SEARCHING";
+ case REGISTRATION_STATE_DENIED: return "DENIED";
+ case REGISTRATION_STATE_UNKNOWN: return "UNKNOWN";
+ case REGISTRATION_STATE_ROAMING: return "ROAMING";
}
- return "Unknown reg state " + regState;
+ return "Unknown reg state " + registrationState;
}
- private static String nrStatusToString(@NRStatus int nrStatus) {
- switch (nrStatus) {
- case NR_STATUS_RESTRICTED:
+ private static String nrStateToString(@NRState int nrState) {
+ switch (nrState) {
+ case NR_STATE_RESTRICTED:
return "RESTRICTED";
- case NR_STATUS_NOT_RESTRICTED:
+ case NR_STATE_NOT_RESTRICTED:
return "NOT_RESTRICTED";
- case NR_STATUS_CONNECTED:
+ case NR_STATE_CONNECTED:
return "CONNECTED";
default:
return "NONE";
@@ -432,75 +460,75 @@
@Override
public String toString() {
- return new StringBuilder("NetworkRegistrationState{")
+ return new StringBuilder("NetworkRegistrationInfo{")
.append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
- .append(" transportType=").append(TransportType.toString(mTransportType))
- .append(" regState=").append(regStateToString(mRegState))
+ .append(" transportType=").append(
+ AccessNetworkConstants.transportTypeToString(mTransportType))
+ .append(" registrationState=").append(registrationStateToString(mRegistrationState))
.append(" roamingType=").append(ServiceState.roamingTypeToString(mRoamingType))
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
.append(" rejectCause=").append(mRejectCause)
.append(" emergencyEnabled=").append(mEmergencyOnly)
.append(" availableServices=").append("[" + (mAvailableServices != null
- ? Arrays.stream(mAvailableServices)
- .mapToObj(type -> serviceTypeToString(type))
+ ? mAvailableServices.stream().map(type -> serviceTypeToString(type))
.collect(Collectors.joining(",")) : null) + "]")
.append(" cellIdentity=").append(mCellIdentity)
.append(" voiceSpecificStates=").append(mVoiceSpecificStates)
.append(" dataSpecificStates=").append(mDataSpecificStates)
- .append(" nrStatus=").append(nrStatusToString(mNrStatus))
+ .append(" nrState=").append(nrStateToString(mNrState))
.append("}").toString();
}
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+ return Objects.hash(mDomain, mTransportType, mRegistrationState, mRoamingType,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
- mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrStatus);
+ mCellIdentity, mVoiceSpecificStates, mDataSpecificStates, mNrState);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
- if (!(o instanceof NetworkRegistrationState)) {
+ if (!(o instanceof NetworkRegistrationInfo)) {
return false;
}
- NetworkRegistrationState other = (NetworkRegistrationState) o;
+ NetworkRegistrationInfo other = (NetworkRegistrationInfo) o;
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
- && mRegState == other.mRegState
+ && mRegistrationState == other.mRegistrationState
&& mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
&& mEmergencyOnly == other.mEmergencyOnly
- && Arrays.equals(mAvailableServices, other.mAvailableServices)
+ && mAvailableServices.equals(other.mAvailableServices)
&& Objects.equals(mCellIdentity, other.mCellIdentity)
&& Objects.equals(mVoiceSpecificStates, other.mVoiceSpecificStates)
&& Objects.equals(mDataSpecificStates, other.mDataSpecificStates)
- && mNrStatus == other.mNrStatus;
+ && mNrState == other.mNrState;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
- dest.writeInt(mRegState);
+ dest.writeInt(mRegistrationState);
dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
dest.writeBoolean(mEmergencyOnly);
- dest.writeIntArray(mAvailableServices);
+ dest.writeList(mAvailableServices);
dest.writeParcelable(mCellIdentity, 0);
dest.writeParcelable(mVoiceSpecificStates, 0);
dest.writeParcelable(mDataSpecificStates, 0);
- dest.writeInt(mNrStatus);
+ dest.writeInt(mNrState);
}
/**
* Use the 5G NR Non-Standalone indicators from the network registration state to update the
- * NR status. There are 3 indicators in the network registration state:
+ * NR state. There are 3 indicators in the network registration state:
*
* 1. if E-UTRA-NR Dual Connectivity (EN-DC) is supported by the primary serving cell.
* 2. if NR is supported by the selected PLMN.
@@ -515,90 +543,81 @@
*
* @param state data specific registration state contains the 5G NR indicators.
*/
- private void updateNrStatus(DataSpecificRegistrationStates state) {
- mNrStatus = NR_STATUS_NONE;
+ private void updateNrState(DataSpecificRegistrationStates state) {
+ mNrState = NR_STATE_NONE;
if (state.isEnDcAvailable) {
if (!state.isDcNrRestricted && state.isNrAvailable) {
- mNrStatus = NR_STATUS_NOT_RESTRICTED;
+ mNrState = NR_STATE_NOT_RESTRICTED;
} else {
- mNrStatus = NR_STATUS_RESTRICTED;
+ mNrState = NR_STATE_RESTRICTED;
}
}
}
- public static final @android.annotation.NonNull Parcelable.Creator<NetworkRegistrationState> CREATOR =
- new Parcelable.Creator<NetworkRegistrationState>() {
- @Override
- public NetworkRegistrationState createFromParcel(Parcel source) {
- return new NetworkRegistrationState(source);
- }
+ public static final @NonNull Parcelable.Creator<NetworkRegistrationInfo> CREATOR =
+ new Parcelable.Creator<NetworkRegistrationInfo>() {
+ @Override
+ public NetworkRegistrationInfo createFromParcel(Parcel source) {
+ return new NetworkRegistrationInfo(source);
+ }
- @Override
- public NetworkRegistrationState[] newArray(int size) {
- return new NetworkRegistrationState[size];
- }
- };
+ @Override
+ public NetworkRegistrationInfo[] newArray(int size) {
+ return new NetworkRegistrationInfo[size];
+ }
+ };
/**
* @hide
*/
- public NetworkRegistrationState sanitizeLocationInfo() {
- NetworkRegistrationState result = copy();
+ public NetworkRegistrationInfo sanitizeLocationInfo() {
+ NetworkRegistrationInfo result = copy();
result.mCellIdentity = null;
return result;
}
- private NetworkRegistrationState copy() {
+ private NetworkRegistrationInfo copy() {
Parcel p = Parcel.obtain();
this.writeToParcel(p, 0);
p.setDataPosition(0);
- NetworkRegistrationState result = new NetworkRegistrationState(p);
+ NetworkRegistrationInfo result = new NetworkRegistrationInfo(p);
p.recycle();
return result;
}
/**
- * Provides a convenient way to set the fields of a {@link NetworkRegistrationState} when
+ * Provides a convenient way to set the fields of a {@link NetworkRegistrationInfo} when
* creating a new instance.
*
- * <p>The example below shows how you might create a new {@code NetworkRegistrationState}:
+ * <p>The example below shows how you might create a new {@code NetworkRegistrationInfo}:
*
* <pre><code>
*
- * NetworkRegistrationState nrs = new NetworkRegistrationState.Builder()
- * .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS)
- * .setApnName("apn.example.com")
- * .setEntryName("Example Carrier APN")
- * .setMmsc(Uri.parse("http://mms.example.com:8002"))
- * .setMmsProxyAddress(mmsProxy)
- * .setMmsProxyPort(8799)
+ * NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ * .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ * .setRegistrationState(REGISTRATION_STATE_HOME)
* .build();
* </code></pre>
*/
- public static class Builder{
+ public static final class Builder{
@Domain
private int mDomain;
+ @TransportType
private int mTransportType;
- @RegState
- private int mRegState;
-
- @ServiceState.RoamingType
- private int mRoamingType;
+ @RegistrationState
+ private int mRegistrationState;
@NetworkType
private int mAccessNetworkTechnology;
- @NRStatus
- private int mNrStatus;
-
private int mRejectCause;
private boolean mEmergencyOnly;
@ServiceType
- private int[] mAvailableServices;
+ private List<Integer> mAvailableServices;
@Nullable
private CellIdentity mCellIdentity;
@@ -627,7 +646,7 @@
*
* @return The same instance of the builder.
*/
- public @NonNull Builder setTransportType(int transportType) {
+ public @NonNull Builder setTransportType(@TransportType int transportType) {
mTransportType = transportType;
return this;
}
@@ -635,24 +654,12 @@
/**
* Set the registration state.
*
- * @param regState The registration state.
+ * @param registrationState The registration state.
*
* @return The same instance of the builder.
*/
- public @NonNull Builder setRegState(@RegState int regState) {
- mRegState = regState;
- return this;
- }
-
- /**
- * Set the roaming type.
- *
- * @param roamingType Roaming type.
- *
- * @return The same instance of the builder.
- */
- public @NonNull Builder setRoamingType(@ServiceState.RoamingType int roamingType) {
- mRoamingType = roamingType;
+ public @NonNull Builder setRegistrationState(@RegistrationState int registrationState) {
+ mRegistrationState = registrationState;
return this;
}
@@ -670,24 +677,13 @@
}
/**
- * Set the 5G NR connection status.
- *
- * @param nrStatus 5G NR connection status.
- *
- * @return The same instance of the builder.
- */
- public @NonNull Builder setNrStatus(@NRStatus int nrStatus) {
- mNrStatus = nrStatus;
- return this;
- }
-
- /**
* Set the network reject cause.
*
* @param rejectCause Reason for denial if the registration state is
- * {@link #REG_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the values are
- * defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2
- * A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set it to 0.
+ * {@link #REGISTRATION_STATE_DENIED}.Depending on {@code accessNetworkTechnology}, the
+ * values are defined in 3GPP TS 24.008 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE,
+ * and 3GPP2 A.S0001 6.2.2.44 for CDMA. If the reject cause is not supported or unknown, set
+ * it to 0.
*
* @return The same instance of the builder.
*/
@@ -716,7 +712,7 @@
* @return The same instance of the builder.
*/
public @NonNull Builder setAvailableServices(
- @NonNull @ServiceType int[] availableServices) {
+ @NonNull @ServiceType List<Integer> availableServices) {
mAvailableServices = availableServices;
return this;
}
@@ -734,12 +730,12 @@
}
/**
- * Build the NetworkRegistrationState.
+ * Build the NetworkRegistrationInfo.
*
- * @return the NetworkRegistrationState object.
+ * @return the NetworkRegistrationInfo object.
*/
- public @NonNull NetworkRegistrationState build() {
- return new NetworkRegistrationState(mDomain, mTransportType, mRegState,
+ public @NonNull NetworkRegistrationInfo build() {
+ return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState,
mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
mCellIdentity);
}
diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java
index f1240e9..bc989dd 100644
--- a/telephony/java/android/telephony/NetworkService.java
+++ b/telephony/java/android/telephony/NetworkService.java
@@ -27,7 +27,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.telephony.NetworkRegistrationState.Domain;
+import android.telephony.NetworkRegistrationInfo.Domain;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,10 +59,10 @@
private static final int NETWORK_SERVICE_CREATE_NETWORK_SERVICE_PROVIDER = 1;
private static final int NETWORK_SERVICE_REMOVE_NETWORK_SERVICE_PROVIDER = 2;
private static final int NETWORK_SERVICE_REMOVE_ALL_NETWORK_SERVICE_PROVIDERS = 3;
- private static final int NETWORK_SERVICE_GET_REGISTRATION_STATE = 4;
- private static final int NETWORK_SERVICE_REGISTER_FOR_STATE_CHANGE = 5;
- private static final int NETWORK_SERVICE_UNREGISTER_FOR_STATE_CHANGE = 6;
- private static final int NETWORK_SERVICE_INDICATION_NETWORK_STATE_CHANGED = 7;
+ private static final int NETWORK_SERVICE_GET_REGISTRATION_INFO = 4;
+ private static final int NETWORK_SERVICE_REGISTER_FOR_INFO_CHANGE = 5;
+ private static final int NETWORK_SERVICE_UNREGISTER_FOR_INFO_CHANGE = 6;
+ private static final int NETWORK_SERVICE_INDICATION_NETWORK_INFO_CHANGED = 7;
private final HandlerThread mHandlerThread;
@@ -86,7 +86,7 @@
private final int mSlotIndex;
private final List<INetworkServiceCallback>
- mNetworkRegistrationStateChangedCallbacks = new ArrayList<>();
+ mNetworkRegistrationInfoChangedCallbacks = new ArrayList<>();
/**
* Constructor
@@ -104,38 +104,38 @@
}
/**
- * API to get network registration state. The result will be passed to the callback.
+ * API to get network registration info. The result will be passed to the callback.
* @param domain Network domain
- * @param callback The callback for reporting network registration state
+ * @param callback The callback for reporting network registration info
*/
- public void getNetworkRegistrationState(@Domain int domain,
- @NonNull NetworkServiceCallback callback) {
- callback.onGetNetworkRegistrationStateComplete(
+ public void getNetworkRegistrationInfo(@Domain int domain,
+ @NonNull NetworkServiceCallback callback) {
+ callback.onGetNetworkRegistrationInfoComplete(
NetworkServiceCallback.RESULT_ERROR_UNSUPPORTED, null);
}
/**
- * Notify the system that network registration state is changed.
+ * Notify the system that network registration info is changed.
*/
- public final void notifyNetworkRegistrationStateChanged() {
- mHandler.obtainMessage(NETWORK_SERVICE_INDICATION_NETWORK_STATE_CHANGED,
+ public final void notifyNetworkRegistrationInfoChanged() {
+ mHandler.obtainMessage(NETWORK_SERVICE_INDICATION_NETWORK_INFO_CHANGED,
mSlotIndex, 0, null).sendToTarget();
}
- private void registerForStateChanged(@NonNull INetworkServiceCallback callback) {
- synchronized (mNetworkRegistrationStateChangedCallbacks) {
- mNetworkRegistrationStateChangedCallbacks.add(callback);
+ private void registerForInfoChanged(@NonNull INetworkServiceCallback callback) {
+ synchronized (mNetworkRegistrationInfoChangedCallbacks) {
+ mNetworkRegistrationInfoChangedCallbacks.add(callback);
}
}
- private void unregisterForStateChanged(@NonNull INetworkServiceCallback callback) {
- synchronized (mNetworkRegistrationStateChangedCallbacks) {
- mNetworkRegistrationStateChangedCallbacks.remove(callback);
+ private void unregisterForInfoChanged(@NonNull INetworkServiceCallback callback) {
+ synchronized (mNetworkRegistrationInfoChangedCallbacks) {
+ mNetworkRegistrationInfoChangedCallbacks.remove(callback);
}
}
- private void notifyStateChangedToCallbacks() {
- for (INetworkServiceCallback callback : mNetworkRegistrationStateChangedCallbacks) {
+ private void notifyInfoChangedToCallbacks() {
+ for (INetworkServiceCallback callback : mNetworkRegistrationInfoChangedCallbacks) {
try {
callback.onNetworkStateChanged();
} catch (RemoteException exception) {
@@ -189,24 +189,24 @@
}
mServiceMap.clear();
break;
- case NETWORK_SERVICE_GET_REGISTRATION_STATE:
+ case NETWORK_SERVICE_GET_REGISTRATION_INFO:
if (serviceProvider == null) break;
int domainId = message.arg2;
- serviceProvider.getNetworkRegistrationState(domainId,
+ serviceProvider.getNetworkRegistrationInfo(domainId,
new NetworkServiceCallback(callback));
break;
- case NETWORK_SERVICE_REGISTER_FOR_STATE_CHANGE:
+ case NETWORK_SERVICE_REGISTER_FOR_INFO_CHANGE:
if (serviceProvider == null) break;
- serviceProvider.registerForStateChanged(callback);
+ serviceProvider.registerForInfoChanged(callback);
break;
- case NETWORK_SERVICE_UNREGISTER_FOR_STATE_CHANGE:
+ case NETWORK_SERVICE_UNREGISTER_FOR_INFO_CHANGE:
if (serviceProvider == null) break;
- serviceProvider.unregisterForStateChanged(callback);
+ serviceProvider.unregisterForInfoChanged(callback);
break;
- case NETWORK_SERVICE_INDICATION_NETWORK_STATE_CHANGED:
+ case NETWORK_SERVICE_INDICATION_NETWORK_INFO_CHANGED:
if (serviceProvider == null) break;
- serviceProvider.notifyStateChangedToCallbacks();
+ serviceProvider.notifyInfoChangedToCallbacks();
break;
default:
break;
@@ -280,23 +280,23 @@
}
@Override
- public void getNetworkRegistrationState(
+ public void getNetworkRegistrationInfo(
int slotIndex, int domain, INetworkServiceCallback callback) {
- mHandler.obtainMessage(NETWORK_SERVICE_GET_REGISTRATION_STATE, slotIndex,
+ mHandler.obtainMessage(NETWORK_SERVICE_GET_REGISTRATION_INFO, slotIndex,
domain, callback).sendToTarget();
}
@Override
- public void registerForNetworkRegistrationStateChanged(
+ public void registerForNetworkRegistrationInfoChanged(
int slotIndex, INetworkServiceCallback callback) {
- mHandler.obtainMessage(NETWORK_SERVICE_REGISTER_FOR_STATE_CHANGE, slotIndex,
+ mHandler.obtainMessage(NETWORK_SERVICE_REGISTER_FOR_INFO_CHANGE, slotIndex,
0, callback).sendToTarget();
}
@Override
- public void unregisterForNetworkRegistrationStateChanged(
+ public void unregisterForNetworkRegistrationInfoChanged(
int slotIndex, INetworkServiceCallback callback) {
- mHandler.obtainMessage(NETWORK_SERVICE_UNREGISTER_FOR_STATE_CHANGE, slotIndex,
+ mHandler.obtainMessage(NETWORK_SERVICE_UNREGISTER_FOR_INFO_CHANGE, slotIndex,
0, callback).sendToTarget();
}
}
diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java
index c2fcfb7..cc25240 100644
--- a/telephony/java/android/telephony/NetworkServiceCallback.java
+++ b/telephony/java/android/telephony/NetworkServiceCallback.java
@@ -28,8 +28,8 @@
/**
* Network service callback. Object of this class is passed to NetworkServiceProvider upon
- * calling getNetworkRegistrationState, to receive asynchronous feedback from NetworkServiceProvider
- * upon onGetNetworkRegistrationStateComplete. It's like a wrapper of INetworkServiceCallback
+ * calling getNetworkRegistrationInfo, to receive asynchronous feedback from NetworkServiceProvider
+ * upon onGetNetworkRegistrationInfoComplete. It's like a wrapper of INetworkServiceCallback
* because INetworkServiceCallback can't be a parameter type in public APIs.
*
* @hide
@@ -70,20 +70,20 @@
/**
* Called to indicate result of
- * {@link NetworkServiceProvider#getNetworkRegistrationState(int, NetworkServiceCallback)}
+ * {@link NetworkServiceProvider#getNetworkRegistrationInfo(int, NetworkServiceCallback)}
*
* @param result Result status like {@link NetworkServiceCallback#RESULT_SUCCESS} or
* {@link NetworkServiceCallback#RESULT_ERROR_UNSUPPORTED}
* @param state The state information to be returned to callback.
*/
- public void onGetNetworkRegistrationStateComplete(int result,
- @Nullable NetworkRegistrationState state) {
+ public void onGetNetworkRegistrationInfoComplete(int result,
+ @Nullable NetworkRegistrationInfo state) {
INetworkServiceCallback callback = mCallback.get();
if (callback != null) {
try {
- callback.onGetNetworkRegistrationStateComplete(result, state);
+ callback.onGetNetworkRegistrationInfoComplete(result, state);
} catch (RemoteException e) {
- Rlog.e(mTag, "Failed to onGetNetworkRegistrationStateComplete on the remote");
+ Rlog.e(mTag, "Failed to onGetNetworkRegistrationInfoComplete on the remote");
}
} else {
Rlog.e(mTag, "Weak reference of callback is null.");
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index bddf978..30dcaa0 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -28,8 +28,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
-import android.telephony.NetworkRegistrationState.Domain;
-import android.telephony.NetworkRegistrationState.NRStatus;
+import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.NetworkRegistrationInfo.Domain;
+import android.telephony.NetworkRegistrationInfo.NRState;
import android.text.TextUtils;
import java.lang.annotation.Retention;
@@ -52,6 +53,9 @@
* <li>Operator name, short name and numeric id
* <li>Network selection mode
* </ul>
+ *
+ * For historical reasons this class is not declared as final; however,
+ * it should be treated as though it were final.
*/
public class ServiceState implements Parcelable {
@@ -348,7 +352,7 @@
* Reference: 3GPP TS 36.104 5.4.3 */
private int mLteEarfcnRsrpBoost = 0;
- private List<NetworkRegistrationState> mNetworkRegistrationStates = new ArrayList<>();
+ private List<NetworkRegistrationInfo> mNetworkRegistrationInfos = new ArrayList<>();
/**
* get String description of roaming type
@@ -431,8 +435,8 @@
mCellBandwidths = s.mCellBandwidths == null ? null :
Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length);
mLteEarfcnRsrpBoost = s.mLteEarfcnRsrpBoost;
- mNetworkRegistrationStates = s.mNetworkRegistrationStates == null ? null :
- new ArrayList<>(s.mNetworkRegistrationStates);
+ mNetworkRegistrationInfos = s.mNetworkRegistrationInfos == null ? null :
+ new ArrayList<>(s.mNetworkRegistrationInfos);
mNrFrequencyRange = s.mNrFrequencyRange;
}
@@ -465,8 +469,8 @@
mIsEmergencyOnly = in.readInt() != 0;
mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
- mNetworkRegistrationStates = new ArrayList<>();
- in.readList(mNetworkRegistrationStates, NetworkRegistrationState.class.getClassLoader());
+ mNetworkRegistrationInfos = new ArrayList<>();
+ in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader());
mChannelNumber = in.readInt();
mCellBandwidths = in.createIntArray();
mNrFrequencyRange = in.readInt();
@@ -494,7 +498,7 @@
out.writeInt(mIsEmergencyOnly ? 1 : 0);
out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
- out.writeList(mNetworkRegistrationStates);
+ out.writeList(mNetworkRegistrationInfos);
out.writeInt(mChannelNumber);
out.writeIntArray(mCellBandwidths);
out.writeInt(mNrFrequencyRange);
@@ -619,8 +623,8 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @RoamingType int getVoiceRoamingType() {
- final NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState != null) {
return regState.getRoamingType();
}
@@ -643,10 +647,11 @@
* @hide
*/
public boolean getDataRoamingFromRegistration() {
- final NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState != null) {
- return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
+ return regState.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
}
return false;
}
@@ -658,8 +663,8 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @RoamingType int getDataRoamingType() {
- final NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState != null) {
return regState.getRoamingType();
}
@@ -837,7 +842,7 @@
mVoiceRegState,
mDataRegState,
mChannelNumber,
- mCellBandwidths,
+ Arrays.hashCode(mCellBandwidths),
mVoiceOperatorAlphaLong,
mVoiceOperatorAlphaShort,
mVoiceOperatorNumeric,
@@ -857,7 +862,7 @@
mIsEmergencyOnly,
mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
- mNetworkRegistrationStates,
+ mNetworkRegistrationInfos,
mNrFrequencyRange);
}
@@ -887,9 +892,9 @@
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
&& mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
- && (mNetworkRegistrationStates == null ? s.mNetworkRegistrationStates == null :
- s.mNetworkRegistrationStates != null &&
- mNetworkRegistrationStates.containsAll(s.mNetworkRegistrationStates))
+ && (mNetworkRegistrationInfos == null
+ ? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null
+ && mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos))
&& mNrFrequencyRange == s.mNrFrequencyRange;
}
@@ -1042,7 +1047,7 @@
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
.append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
- .append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates)
+ .append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
.append(", mNrFrequencyRange=").append(mNrFrequencyRange)
.append("}").toString();
}
@@ -1072,7 +1077,7 @@
mIsEmergencyOnly = false;
mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
- mNetworkRegistrationStates = new ArrayList<>();
+ mNetworkRegistrationInfos = new ArrayList<>();
mNrFrequencyRange = FREQUENCY_RANGE_UNKNOWN;
}
@@ -1129,14 +1134,14 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setVoiceRoamingType(@RoamingType int type) {
- NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) {
- regState = new NetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
- ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
- false, null, null);
- addNetworkRegistrationState(regState);
+ regState = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .build();
+ addNetworkRegistrationInfo(regState);
}
regState.setRoamingType(type);
}
@@ -1150,14 +1155,14 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setDataRoamingType(@RoamingType int type) {
- NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) {
- regState = new NetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
- ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
- false, null, null);
- addNetworkRegistrationState(regState);
+ regState = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .build();
+ addNetworkRegistrationInfo(regState);
}
regState.setRoamingType(type);
}
@@ -1325,14 +1330,14 @@
this.mRilVoiceRadioTechnology = rt;
// sync to network registration state
- NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) {
- regState = new NetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
- ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- 0, false, null, null);
- addNetworkRegistrationState(regState);
+ regState = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .build();
+ addNetworkRegistrationInfo(regState);
}
regState.setAccessNetworkTechnology(
rilRadioTechnologyToNetworkType(mRilVoiceRadioTechnology));
@@ -1352,15 +1357,15 @@
mRilDataRadioTechnology);
// sync to network registration state
- NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) {
- regState = new NetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
- ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN,
- 0, false, null, null);
- addNetworkRegistrationState(regState);
+ regState = new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .build();
+ addNetworkRegistrationInfo(regState);
}
regState.setAccessNetworkTechnology(
rilRadioTechnologyToNetworkType(mRilDataRadioTechnology));
@@ -1385,15 +1390,15 @@
}
/**
- * Get the NR 5G status of the mobile data network.
- * @return the NR 5G status.
+ * Get the NR 5G state of the mobile data network.
+ * @return the NR 5G state.
* @hide
*/
- public @NRStatus int getNrStatus() {
- final NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
- if (regState == null) return NetworkRegistrationState.NR_STATUS_NONE;
- return regState.getNrStatus();
+ public @NRState int getNrState() {
+ final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (regState == null) return NetworkRegistrationInfo.NR_STATE_NONE;
+ return regState.getNrState();
}
/**
@@ -1575,19 +1580,19 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @TelephonyManager.NetworkType int getDataNetworkType() {
- final NetworkRegistrationState iwlanRegState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WLAN);
- if (iwlanRegState != null
- && iwlanRegState.getRegState() == NetworkRegistrationState.REG_STATE_HOME) {
+ final NetworkRegistrationInfo iwlanRegState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ if (iwlanRegState != null && iwlanRegState.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
// If the device is on IWLAN, return IWLAN as the network type. This is to simulate the
// behavior of legacy mode device. In the future caller should use
- // getNetworkRegistrationState() to retrieve the actual data network type on cellular
+ // getNetworkRegistrationInfo() to retrieve the actual data network type on cellular
// or on IWLAN.
return iwlanRegState.getAccessNetworkTechnology();
}
- final NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState != null) {
return regState.getAccessNetworkTechnology();
}
@@ -1597,8 +1602,8 @@
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
public @TelephonyManager.NetworkType int getVoiceNetworkType() {
- final NetworkRegistrationState regState = getNetworkRegistrationState(
- NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ final NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState != null) {
return regState.getAccessNetworkTechnology();
}
@@ -1761,52 +1766,36 @@
}
/**
- * Get all of the available network registration states.
+ * Get all of the available network registration info.
*
- * @return List of {@link NetworkRegistrationState}
+ * @return List of {@link NetworkRegistrationInfo}
* @hide
*/
@NonNull
@SystemApi
- public List<NetworkRegistrationState> getNetworkRegistrationStates() {
- synchronized (mNetworkRegistrationStates) {
- return new ArrayList<>(mNetworkRegistrationStates);
+ public List<NetworkRegistrationInfo> getNetworkRegistrationInfoList() {
+ synchronized (mNetworkRegistrationInfos) {
+ return new ArrayList<>(mNetworkRegistrationInfos);
}
}
/**
- * Get the network registration states for the transport type.
+ * Get the network registration info list for the transport type.
*
- * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
- * @return List of {@link NetworkRegistrationState}
- * @hide
- *
- * @deprecated Use {@link #getNetworkRegistrationStatesFromTransportType(int)}
- */
- @NonNull
- @Deprecated
- @SystemApi
- public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
- return getNetworkRegistrationStatesForTransportType(transportType);
- }
-
- /**
- * Get the network registration states for the transport type.
- *
- * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
- * @return List of {@link NetworkRegistrationState}
+ * @param transportType The transport type
+ * @return List of {@link NetworkRegistrationInfo}
* @hide
*/
@NonNull
@SystemApi
- public List<NetworkRegistrationState> getNetworkRegistrationStatesForTransportType(
- int transportType) {
- List<NetworkRegistrationState> list = new ArrayList<>();
+ public List<NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(
+ @TransportType int transportType) {
+ List<NetworkRegistrationInfo> list = new ArrayList<>();
- synchronized (mNetworkRegistrationStates) {
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType) {
- list.add(networkRegistrationState);
+ synchronized (mNetworkRegistrationInfos) {
+ for (NetworkRegistrationInfo networkRegistrationInfo : mNetworkRegistrationInfos) {
+ if (networkRegistrationInfo.getTransportType() == transportType) {
+ list.add(networkRegistrationInfo);
}
}
}
@@ -1815,22 +1804,22 @@
}
/**
- * Get the network registration states for the network domain.
+ * Get the network registration info list for the network domain.
*
- * @param domain The network {@link NetworkRegistrationState.Domain domain}
- * @return List of {@link NetworkRegistrationState}
+ * @param domain The network {@link NetworkRegistrationInfo.Domain domain}
+ * @return List of {@link NetworkRegistrationInfo}
* @hide
*/
@NonNull
@SystemApi
- public List<NetworkRegistrationState> getNetworkRegistrationStatesForDomain(
+ public List<NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(
@Domain int domain) {
- List<NetworkRegistrationState> list = new ArrayList<>();
+ List<NetworkRegistrationInfo> list = new ArrayList<>();
- synchronized (mNetworkRegistrationStates) {
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getDomain() == domain) {
- list.add(networkRegistrationState);
+ synchronized (mNetworkRegistrationInfos) {
+ for (NetworkRegistrationInfo networkRegistrationInfo : mNetworkRegistrationInfos) {
+ if (networkRegistrationInfo.getDomain() == domain) {
+ list.add(networkRegistrationInfo);
}
}
}
@@ -1841,39 +1830,21 @@
/**
* Get the network registration state for the transport type and network domain.
*
- * @param domain The network {@link NetworkRegistrationState.Domain domain}
- * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
- * @return The matching {@link NetworkRegistrationState}
- * @hide
- *
- * @deprecated Use {@link #getNetworkRegistrationState(int, int)}
- */
- @Nullable
- @Deprecated
- @SystemApi
- public NetworkRegistrationState getNetworkRegistrationStates(@Domain int domain,
- int transportType) {
- return getNetworkRegistrationState(domain, transportType);
- }
-
- /**
- * Get the network registration state for the transport type and network domain.
- *
- * @param domain The network {@link NetworkRegistrationState.Domain domain}
- * @param transportType The {@link AccessNetworkConstants.TransportType transport type}
- * @return The matching {@link NetworkRegistrationState}
+ * @param domain The network {@link NetworkRegistrationInfo.Domain domain}
+ * @param transportType The transport type
+ * @return The matching {@link NetworkRegistrationInfo}
* @hide
*
*/
@Nullable
@SystemApi
- public NetworkRegistrationState getNetworkRegistrationState(@Domain int domain,
- int transportType) {
- synchronized (mNetworkRegistrationStates) {
- for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
- if (networkRegistrationState.getTransportType() == transportType
- && networkRegistrationState.getDomain() == domain) {
- return networkRegistrationState;
+ public NetworkRegistrationInfo getNetworkRegistrationInfo(@Domain int domain,
+ @TransportType int transportType) {
+ synchronized (mNetworkRegistrationInfos) {
+ for (NetworkRegistrationInfo networkRegistrationInfo : mNetworkRegistrationInfos) {
+ if (networkRegistrationInfo.getTransportType() == transportType
+ && networkRegistrationInfo.getDomain() == domain) {
+ return networkRegistrationInfo;
}
}
}
@@ -1884,20 +1855,20 @@
/**
* @hide
*/
- public void addNetworkRegistrationState(NetworkRegistrationState regState) {
+ public void addNetworkRegistrationInfo(NetworkRegistrationInfo regState) {
if (regState == null) return;
- synchronized (mNetworkRegistrationStates) {
- for (int i = 0; i < mNetworkRegistrationStates.size(); i++) {
- NetworkRegistrationState curRegState = mNetworkRegistrationStates.get(i);
+ synchronized (mNetworkRegistrationInfos) {
+ for (int i = 0; i < mNetworkRegistrationInfos.size(); i++) {
+ NetworkRegistrationInfo curRegState = mNetworkRegistrationInfos.get(i);
if (curRegState.getTransportType() == regState.getTransportType()
&& curRegState.getDomain() == regState.getDomain()) {
- mNetworkRegistrationStates.remove(i);
+ mNetworkRegistrationInfos.remove(i);
break;
}
}
- mNetworkRegistrationStates.add(regState);
+ mNetworkRegistrationInfos.add(regState);
}
}
@@ -1912,15 +1883,15 @@
/**
* Returns a copy of self with location-identifying information removed.
- * Always clears the NetworkRegistrationState's CellIdentity fields, but if removeCoarseLocation
+ * Always clears the NetworkRegistrationInfo's CellIdentity fields, but if removeCoarseLocation
* is true, clears other info as well.
* @hide
*/
public ServiceState sanitizeLocationInfo(boolean removeCoarseLocation) {
ServiceState state = new ServiceState(this);
- if (state.mNetworkRegistrationStates != null) {
- state.mNetworkRegistrationStates = state.mNetworkRegistrationStates.stream()
- .map(NetworkRegistrationState::sanitizeLocationInfo)
+ if (state.mNetworkRegistrationInfos != null) {
+ state.mNetworkRegistrationInfos = state.mNetworkRegistrationInfos.stream()
+ .map(NetworkRegistrationInfo::sanitizeLocationInfo)
.collect(Collectors.toList());
}
if (!removeCoarseLocation) return state;
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 245f5b3..ac11940 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -161,11 +161,6 @@
private String mGroupUUID;
/**
- * A property in opportunistic subscription to indicate whether it is metered or not.
- */
- private boolean mIsMetered;
-
- /**
* Whether group of the subscription is disabled.
* This is only useful if it's a grouped opportunistic subscription. In this case, if all
* primary (non-opportunistic) subscriptions in the group are deactivated (unplugged pSIM
@@ -197,7 +192,7 @@
@Nullable UiccAccessRule[] accessRules, String cardString) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
- false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+ false, null, TelephonyManager.UNKNOWN_CARRIER_ID,
SubscriptionManager.PROFILE_CLASS_DEFAULT);
}
@@ -208,10 +203,10 @@
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
@Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
- @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
+ @Nullable String groupUUID, int carrierId, int profileClass) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
- isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
+ isOpportunistic, groupUUID, false, carrierId, profileClass,
SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
}
@@ -222,7 +217,7 @@
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
@Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
- boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
+ boolean isOpportunistic, @Nullable String groupUUID,
boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
this.mId = id;
this.mIccId = iccId;
@@ -243,7 +238,6 @@
this.mCardId = cardId;
this.mIsOpportunistic = isOpportunistic;
this.mGroupUUID = groupUUID;
- this.mIsMetered = isMetered;
this.mIsGroupDisabled = isGroupDisabled;
this.mCarrierId = carrierId;
this.mProfileClass = profileClass;
@@ -472,18 +466,6 @@
}
/**
- * Used in opportunistic subscription ({@link #isOpportunistic()}) to indicate whether it's
- * metered or not.This is one of the factors when deciding to switch to the subscription.
- * (a non-metered subscription, for example, would likely be preferred over a metered one).
- *
- * @return whether subscription is metered.
- * @hide
- */
- public boolean isMetered() {
- return mIsMetered;
- }
-
- /**
* @return the profile class of this subscription.
* @hide
*/
@@ -624,7 +606,6 @@
int cardId = source.readInt();
boolean isOpportunistic = source.readBoolean();
String groupUUID = source.readString();
- boolean isMetered = source.readBoolean();
boolean isGroupDisabled = source.readBoolean();
int carrierid = source.readInt();
int profileClass = source.readInt();
@@ -633,7 +614,7 @@
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
- isMetered, isGroupDisabled, carrierid, profileClass, subType);
+ isGroupDisabled, carrierid, profileClass, subType);
}
@Override
@@ -663,7 +644,6 @@
dest.writeInt(mCardId);
dest.writeBoolean(mIsOpportunistic);
dest.writeString(mGroupUUID);
- dest.writeBoolean(mIsMetered);
dest.writeBoolean(mIsGroupDisabled);
dest.writeInt(mCarrierId);
dest.writeInt(mProfileClass);
@@ -703,7 +683,7 @@
+ " accessRules " + Arrays.toString(mAccessRules)
+ " cardString=" + cardStringToPrint + " cardId=" + mCardId
+ " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
- + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+ + " mIsGroupDisabled=" + mIsGroupDisabled
+ " profileClass=" + mProfileClass
+ " subscriptionType=" + mSubscriptionType + "}";
}
@@ -711,7 +691,7 @@
@Override
public int hashCode() {
return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
- mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
+ mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
mIsGroupDisabled, mCarrierId, mProfileClass);
}
@@ -737,7 +717,6 @@
&& mIsOpportunistic == toCompare.mIsOpportunistic
&& mIsGroupDisabled == toCompare.mIsGroupDisabled
&& mCarrierId == toCompare.mCarrierId
- && mIsMetered == toCompare.mIsMetered
&& Objects.equals(mGroupUUID, toCompare.mGroupUUID)
&& Objects.equals(mIccId, toCompare.mIccId)
&& Objects.equals(mNumber, toCompare.mNumber)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 3707aa4..2edef83 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2595,7 +2595,9 @@
* {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
* it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
* is used to determine which modem is preferred.
- * @param needValidation whether validation is needed before switch happens.
+ * @param needValidation whether Telephony will wait until the network is validated by
+ * connectivity service before switching data to it. More details see
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}.
* @param executor The executor of where the callback will execute.
* @param callback Callback will be triggered once it succeeds or failed.
* See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
@@ -2853,29 +2855,6 @@
}
/**
- * Set if a subscription is metered or not. Similar to Wi-Fi, metered means
- * user may be charged more if more data is used.
- *
- * By default all Cellular networks are considered metered. System or carrier privileged apps
- * can set a subscription un-metered which will be considered when system switches data between
- * primary subscription and opportunistic subscription.
- *
- * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
- * privilege permission of the subscription.
- *
- * @param isMetered whether it’s a metered subscription.
- * @param subId the unique SubscriptionInfo index in database
- * @return {@code true} if the operation is succeed, {@code false} otherwise.
- */
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public boolean setMetered(boolean isMetered, int subId) {
- if (VDBG) logd("[setIsMetered]+ isMetered:" + isMetered + " subId:" + subId);
- return setSubscriptionPropertyHelper(subId, "setIsMetered",
- (iSub)-> iSub.setMetered(isMetered, subId, mContext.getOpPackageName())) == 1;
- }
-
- /**
* Whether a subscription is visible to API caller. If it's a bundled opportunistic
* subscription, it should be hidden anywhere in Settings, dialer, status bar etc.
* Exception is if caller owns carrier privilege, in which case they will
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3dee114..1eb6cc3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -58,6 +58,8 @@
import android.os.WorkSource;
import android.provider.Settings.SettingNotFoundException;
import android.service.carrier.CarrierIdentifier;
+import android.telecom.CallScreeningService;
+import android.telecom.InCallService;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -617,7 +619,13 @@
* <p class="note">
* Retrieve with
* {@link android.content.Intent#getStringExtra(String)}.
+ * <p>
+ *
+ * @deprecated Companion apps for wearable devices should use the {@link InCallService} API
+ * to retrieve the phone number for calls instead. Apps performing call screening should use
+ * the {@link CallScreeningService} API instead.
*/
+ @Deprecated
public static final String EXTRA_INCOMING_NUMBER = "incoming_number";
/**
@@ -3346,26 +3354,25 @@
}
/**
- * Get the mapping from logical slots to physical slots. The mapping represent by a pair list.
- * The key of the piar is the logical slot id and the value of the pair is the physical
- * slots id mapped to this logical slot id.
+ * Get the mapping from logical slots to physical slots. The key of the map is the logical slot
+ * id and the value is the physical slots id mapped to this logical slot id.
*
- * @return an pair list indicates the mapping from logical slots to physical slots. The size of
- * the list should be {@link #getPhoneCount()} if success, otherwise return an empty list.
+ * @return a map indicates the mapping from logical slots to physical slots. The size of the map
+ * should be {@link #getPhoneCount()} if success, otherwise return an empty map.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@NonNull
- public List<Pair<Integer, Integer>> getLogicalToPhysicalSlotMapping() {
- List<Pair<Integer, Integer>> slotMapping = new ArrayList<>();
+ public Map<Integer, Integer> getLogicalToPhysicalSlotMapping() {
+ Map<Integer, Integer> slotMapping = new HashMap<>();
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
int[] slotMappingArray = telephony.getSlotsMapping();
for (int i = 0; i < slotMappingArray.length; i++) {
- slotMapping.add(new Pair(i, slotMappingArray[i]));
+ slotMapping.put(i, slotMappingArray[i]);
}
}
} catch (RemoteException e) {
@@ -4772,18 +4779,22 @@
* Registers a listener object to receive notification of changes
* in specified telephony states.
* <p>
- * To register a listener, pass a {@link PhoneStateListener}
- * and specify at least one telephony state of interest in
- * the events argument.
+ * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
+ * state of interest in the events argument.
*
- * At registration, and when a specified telephony state
- * changes, the telephony manager invokes the appropriate
- * callback method on the listener object and passes the
- * current (updated) values.
+ * At registration, and when a specified telephony state changes, the telephony manager invokes
+ * the appropriate callback method on the listener object and passes the current (updated)
+ * values.
* <p>
- * To unregister a listener, pass the listener object and set the
- * events argument to
+ * To un-register a listener, pass the listener object and set the events argument to
* {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
+ *
+ * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
+ * applies to the given subId. Otherwise, applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
+ * pass a separate listener object to each TelephonyManager object created with
+ * {@link #createForSubscriptionId}.
+ *
* Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
* call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
* {@link SecurityException} will be thrown otherwise.
@@ -4798,17 +4809,18 @@
if (mContext == null) return;
try {
boolean notifyNow = (getITelephony() != null);
- // If the listener has not explicitly set the subId (for example, created with the
- // default constructor), replace the subId so it will listen to the account the
- // telephony manager is created with.
- if (listener.mSubId == null) {
- listener.mSubId = mSubId;
- }
-
ITelephonyRegistry registry = getTelephonyRegistry();
if (registry != null) {
- registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+ // listen to the subId the telephony manager is created with. Ignore subId in
+ // PhoneStateListener.
+ registry.listenForSubscriber(mSubId, getOpPackageName(),
listener.callback, events, notifyNow);
+ // TODO: remove this once we remove PhoneStateListener constructor with subId.
+ if (events == PhoneStateListener.LISTEN_NONE) {
+ listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ } else {
+ listener.mSubId = mSubId;
+ }
} else {
Rlog.w(TAG, "telephony registry not ready.");
}
@@ -8286,7 +8298,7 @@
* @see SubscriptionManager#getDefaultSubscriptionId()
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public boolean isVolteAvailable() {
try {
return getITelephony().isAvailable(getSubId(),
@@ -8305,7 +8317,7 @@
* @return true if VT is available, or false if it is unavailable or unknown.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public boolean isVideoTelephonyAvailable() {
try {
return getITelephony().isVideoTelephonyAvailable(getSubId());
@@ -8320,7 +8332,7 @@
* @return true if VoWiFi is available, or false if it is unavailable or unknown.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+ @UnsupportedAppUsage
public boolean isWifiCallingAvailable() {
try {
return getITelephony().isWifiCallingAvailable(getSubId());
@@ -9858,8 +9870,11 @@
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
*
+ *
+ * @deprecated
* @hide
*/
+ @Deprecated
@TestApi
public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
String gid2, String plmn, String spn) {
@@ -9867,7 +9882,35 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
telephony.setCarrierTestOverride(
- getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+ getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+ null, null);
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ }
+
+ /**
+ * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+ * plmn, spn, apn and carrier priviledge. This would be handy for, eg, forcing a particular
+ * carrier id, carrier's config (also any country or carrier overlays) to be loaded when using
+ * a test SIM with a call box.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ */
+ @TestApi
+ public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+ String gid2, String plmn, String spn,
+ String carrierPriviledgeRules, String apn) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setCarrierTestOverride(
+ getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn,
+ carrierPriviledgeRules, apn);
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
@@ -10256,15 +10299,20 @@
}
/**
- * Checks if the supplied number is an emergency number based on current locale, sim, default,
- * modem and network.
+ * Identifies if the supplied phone number is an emergency number that matches a known
+ * emergency number based on current locale, SIM card(s), Android database, modem, network,
+ * or defaults.
+ *
+ * <p>This method assumes that only dialable phone numbers are passed in; non-dialable
+ * numbers are not considered emergency numbers. A dialable phone number consists only
+ * of characters/digits identified by {@link PhoneNumberUtils#isDialable(char)}.
*
* <p>The subscriptions which the identification would be based on, are all the active
* subscriptions, no matter which subscription could be used to create TelephonyManager.
*
* @param number - the number to look up
* @return {@code true} if the given number is an emergency number based on current locale,
- * sim, modem and network; {@code false} otherwise.
+ * SIM card(s), Android database, modem, network or defaults; {@code false} otherwise.
*/
public boolean isEmergencyNumber(@NonNull String number) {
try {
@@ -10325,7 +10373,7 @@
@IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
SET_OPPORTUNISTIC_SUB_SUCCESS,
SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
- SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+ SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
public @interface SetOpportunisticSubscriptionResult {}
/**
@@ -10339,9 +10387,9 @@
public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
/**
- * The parameter passed in is invalid.
+ * The subscription is not valid. It must be an active opportunistic subscription.
*/
- public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+ public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -10561,45 +10609,77 @@
* <p>Note: the API does not prevent access to the SIM cards for operations that don't require
* access to the network.
*
- * @param isMultisimCarrierRestricted true if usage of multiple SIMs is restricted, false
+ * @param isMultiSimCarrierRestricted true if usage of multiple SIMs is restricted, false
* otherwise.
*
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted) {
+ public void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted) {
try {
ITelephony service = getITelephony();
if (service != null) {
- service.setMultisimCarrierRestriction(isMultisimCarrierRestricted);
+ service.setMultiSimCarrierRestriction(isMultiSimCarrierRestricted);
}
} catch (RemoteException e) {
- Log.e(TAG, "setMultisimCarrierRestriction RemoteException", e);
+ Log.e(TAG, "setMultiSimCarrierRestriction RemoteException", e);
}
}
/**
+ * The usage of multiple SIM cards at the same time to register on the network (e.g. Dual
+ * Standby or Dual Active) is supported.
+ */
+ public static final int MULTISIM_ALLOWED = 0;
+
+ /**
+ * The usage of multiple SIM cards at the same time to register on the network (e.g. Dual
+ * Standby or Dual Active) is not supported by the hardware.
+ */
+ public static final int MULTISIM_NOT_SUPPORTED_BY_HARDWARE = 1;
+
+ /**
+ * The usage of multiple SIM cards at the same time to register on the network (e.g. Dual
+ * Standby or Dual Active) is supported by the hardware, but restricted by the carrier.
+ */
+ public static final int MULTISIM_NOT_SUPPORTED_BY_CARRIER = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"MULTISIM_"},
+ value = {
+ MULTISIM_ALLOWED,
+ MULTISIM_NOT_SUPPORTED_BY_HARDWARE,
+ MULTISIM_NOT_SUPPORTED_BY_CARRIER
+ })
+ public @interface IsMultiSimSupportedResult {}
+
+ /**
* Returns if the usage of multiple SIM cards at the same time to register on the network
* (e.g. Dual Standby or Dual Active) is supported by the device and by the carrier.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
*
- * @return true if usage of multiple SIMs is supported, false otherwise.
+ * @return {@link #MULTISIM_ALLOWED} if the device supports multiple SIMs.
+ * {@link #MULTISIM_NOT_SUPPORTED_BY_HARDWARE} if the device does not support multiple SIMs.
+ * {@link #MULTISIM_NOT_SUPPORTED_BY_CARRIER} in the device supports multiple SIMs, but the
+ * functionality is restricted by the carrier.
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public boolean isMultisimSupported() {
+ @IsMultiSimSupportedResult
+ public int isMultiSimSupported() {
try {
ITelephony service = getITelephony();
if (service != null) {
- return service.isMultisimSupported(getOpPackageName());
+ return service.isMultiSimSupported(getOpPackageName());
}
} catch (RemoteException e) {
- Log.e(TAG, "isMultisimSupported RemoteException", e);
+ Log.e(TAG, "isMultiSimSupported RemoteException", e);
}
- return false;
+ return MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
}
/**
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 173f4ed..fa6cfcb 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -22,6 +22,7 @@
import android.hardware.radio.V1_4.EmergencyServiceCategory;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.PhoneNumberUtils;
import android.telephony.Rlog;
import java.lang.annotation.Retention;
@@ -673,11 +674,20 @@
}
/**
- * Validate Emergency Number address that only allows '0'-'9', '*', or '#'
+ * Validate Emergency Number address that only contains the dialable character
+ * {@link PhoneNumberUtils#isDialable(char)}
*
* @hide
*/
public static boolean validateEmergencyNumberAddress(String address) {
- return address.matches("[0-9*#]+");
+ if (address == null) {
+ return false;
+ }
+ for (char c : address.toCharArray()) {
+ if (!PhoneNumberUtils.isDialable(c)) {
+ return false;
+ }
+ }
+ return true;
}
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index bac8c03..cde10ea 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -118,7 +118,11 @@
/**
* Intent action sent by system apps (such as the Settings app) to the Telephony framework to
* enable or disable a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
- * {@link #EXTRA_ENABLE_SUBSCRIPTION}.
+ * {@link #EXTRA_ENABLE_SUBSCRIPTION}, and optionally {@link #EXTRA_FROM_SUBSCRIPTION_ID}.
+ *
+ * <p>Requires the caller to be a privileged process with the
+ * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
+ * stack.
*
* <p>Unlike {@link #switchToSubscription(int, PendingIntent)}, using this action allows the
* underlying eUICC service (i.e. the LPA app) to control the UI experience during this
@@ -139,6 +143,10 @@
* Intent action sent by system apps (such as the Settings app) to the Telephony framework to
* delete a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID}.
*
+ * <p>Requires the caller to be a privileged process with the
+ * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
+ * stack.
+ *
* <p>Unlike {@link #deleteSubscription(int, PendingIntent)}, using this action allows the
* underlying eUICC service (i.e. the LPA app) to control the UI experience during this
* operation. The action is received by the Telephony framework, which in turn selects and
@@ -159,6 +167,10 @@
* rename a subscription. Must be accompanied with {@link #EXTRA_SUBSCRIPTION_ID} and
* {@link #EXTRA_SUBSCRIPTION_NICKNAME}.
*
+ * <p>Requires the caller to be a privileged process with the
+ * {@link android.permission#CALL_PRIVILEGED} permission for the intent to reach the Telephony
+ * stack.
+ *
* <p>Unlike {@link #updateSubscriptionNickname(int, String, PendingIntent)}, using this action
* allows the the underlying eUICC service (i.e. the LPA app) to control the UI experience
* during this operation. The action is received by the Telephony framework, which in turn
@@ -273,6 +285,8 @@
* {@link #ACTION_DELETE_SUBSCRIPTION_PRIVILEGED}, and
* {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing the ID of the targeted subscription.
*
+ * <p>Expected type of the extra data: int
+ *
* @hide
*/
@SystemApi
@@ -283,6 +297,8 @@
* Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing a boolean
* value of whether to enable or disable the targeted subscription.
*
+ * <p>Expected type of the extra data: boolean
+ *
* @hide
*/
@SystemApi
@@ -293,6 +309,8 @@
* Key for an extra set on {@link #ACTION_RENAME_SUBSCRIPTION_PRIVILEGED} providing a new
* nickname for the targeted subscription.
*
+ * <p>Expected type of the extra data: String
+ *
* @hide
*/
@SystemApi
@@ -300,6 +318,22 @@
"android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
/**
+ * Key for an extra set on {@link #ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED} providing the ID of
+ * the subscription we're toggling from. This extra is optional and is only used for UI
+ * purposes by the underlying eUICC service (i.e. the LPA app), such as displaying a dialog
+ * titled "Switch X with Y". If set, the provided subscription will be used as the "from"
+ * subscription in UI (the "X" in the dialog example). Otherwise, the currently active
+ * subscription that will be disabled is the "from" subscription.
+ *
+ * <p>Expected type of the extra data: int
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_FROM_SUBSCRIPTION_ID =
+ "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
+
+ /**
* Optional meta-data attribute for a carrier app providing an icon to use to represent the
* carrier. If not provided, the app's launcher icon will be used as a fallback.
*/
@@ -761,7 +795,7 @@
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void updateSubscriptionNickname(
- int subscriptionId, String nickname, PendingIntent callbackIntent) {
+ int subscriptionId, @Nullable String nickname, @NonNull PendingIntent callbackIntent) {
if (!refreshCardIdIfUninitialized()) {
sendUnavailableError(callbackIntent);
return;
diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java
index 02eddf6..8c686f7 100644
--- a/telephony/java/android/telephony/ims/ImsException.java
+++ b/telephony/java/android/telephony/ims/ImsException.java
@@ -31,7 +31,7 @@
* @hide
*/
@SystemApi
-public class ImsException extends Exception {
+public final class ImsException extends Exception {
/**
* The operation has failed due to an unknown or unspecified error.
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 12e8006..e9aede7 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -109,9 +109,9 @@
// case, since it is defined.
put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
- AccessNetworkConstants.TransportType.WWAN);
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
- AccessNetworkConstants.TransportType.WLAN);
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
}};
private final RegistrationCallback mLocalCallback;
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 79e0aa1..3bbf7a4 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -205,15 +205,6 @@
String setSubscriptionGroup(in int[] subIdList, String callingPackage);
/**
- * Set whether a subscription is metered
- *
- * @param isMetered whether it’s a metered subscription.
- * @param subId the unique SubscriptionInfo index in database
- * @return the number of records updated
- */
- int setMetered(boolean isMetered, int subId, String callingPackage);
-
- /**
* Set which subscription is preferred for cellular data. It's
* designed to overwrite default data subscription temporarily.
*
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 62b92fd..10cc99e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1683,7 +1683,7 @@
* (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
*/
void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
- String gid2, String plmn, String spn);
+ String gid2, String plmn, String spn, String carrierPrivilegeRules, String apn);
/**
* A test API to return installed carrier id list version.
@@ -1919,15 +1919,18 @@
* Indicate if the enablement of multi SIM functionality is restricted.
* @hide
*/
- void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted);
+ void setMultiSimCarrierRestriction(boolean isMultiSimCarrierRestricted);
/**
* Returns if the usage of multiple SIM cards at the same time is supported.
*
* @param callingPackage The package making the call.
- * @return true if multisim is supported, false otherwise.
+ * @return {@link #MULTISIM_ALLOWED} if the device supports multiple SIMs.
+ * {@link #MULTISIM_NOT_SUPPORTED_BY_HARDWARE} if the device does not support multiple SIMs.
+ * {@link #MULTISIM_NOT_SUPPORTED_BY_CARRIER} in the device supports multiple SIMs, but the
+ * functionality is restricted by the carrier.
*/
- boolean isMultisimSupported(String callingPackage);
+ int isMultiSimSupported(String callingPackage);
/**
* Switch configs to enable multi-sim or switch back to single-sim
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 9d78bf4..4886a3f 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -317,7 +317,8 @@
Settings.Global.PRIVILEGED_DEVICE_IDENTIFIER_PRIV_CHECK_RELAXED, 0) == 1;
ApplicationInfo callingPackageInfo = null;
try {
- callingPackageInfo = context.getPackageManager().getApplicationInfo(callingPackage, 0);
+ callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
+ callingPackage, 0, UserHandle.getUserId(uid));
if (callingPackageInfo.isSystemApp()) {
isPreinstalled = true;
if (callingPackageInfo.isPrivilegedApp()) {
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index b31235b..41cb74a 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -4,7 +4,7 @@
-->
<configuration description="Runs WindowManager Flicker Tests">
<option name="test-tag" value="FlickerTests" />
- <target_preparer class="com.google.android.tradefed.targetprep.GoogleDeviceSetup">
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<!-- keeps the screen on during tests -->
<option name="screen-always-on" value="on" />
<!-- prevents the phone from restarting -->
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
index 8a925b9..ebe5418 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -63,6 +63,13 @@
}
/**
+ * Waits forever for the next rollback broadcast.
+ */
+ Intent take() throws InterruptedException {
+ return mRollbackBroadcasts.take();
+ }
+
+ /**
* Unregisters this broadcast receiver.
*/
void unregister() {
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 7505230..834743d 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -27,7 +27,6 @@
import static org.junit.Assert.fail;
import android.Manifest;
-import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -40,14 +39,11 @@
import androidx.test.InstrumentationRegistry;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.Collections;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
/**
@@ -87,6 +83,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.MANAGE_ROLLBACKS);
// Register a broadcast receiver for notification when the
@@ -175,7 +172,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -233,7 +230,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -290,7 +287,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -343,11 +340,11 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.WRITE_DEVICE_CONFIG);
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(expirationTime), false /* makeDefault*/);
// Pull the new expiration time from DeviceConfig
@@ -382,8 +379,8 @@
assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
} finally {
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(defaultExpirationTime), false /* makeDefault*/);
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -403,12 +400,12 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.WRITE_DEVICE_CONFIG,
Manifest.permission.SET_TIME);
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(expirationTime), false /* makeDefault*/);
// Pull the new expiration time from DeviceConfig
@@ -458,8 +455,8 @@
RollbackTestUtils.forwardTimeBy(-expirationTime);
}
} finally {
- DeviceConfig.setProperty(DeviceConfig.Rollback.BOOT_NAMESPACE,
- DeviceConfig.Rollback.ROLLBACK_LIFETIME_IN_MILLIS,
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK_BOOT,
+ RollbackManager.PROPERTY_ROLLBACK_LIFETIME_MILLIS,
Long.toString(defaultExpirationTime), false /* makeDefault*/);
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -475,7 +472,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
RollbackTestUtils.uninstall(TEST_APP_A);
@@ -512,7 +509,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackTestUtils.uninstall(TEST_APP_A);
RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -533,14 +530,13 @@
/**
* Test rollback of apks involving splits.
*/
- @Ignore("b/127520966 build issues with splits need to be sorted out")
@Test
public void testRollbackWithSplits() throws Exception {
try {
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackTestUtils.uninstall(TEST_APP_A);
RollbackTestUtils.installSplit(false,
@@ -598,7 +594,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
// Prep installation of the test apps.
@@ -693,6 +689,75 @@
}
/**
+ * Test that you cannot enable rollback for a package without the
+ * MANAGE_ROLLBACKS permission.
+ */
+ @Test
+ public void testEnableRollbackPermission() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES);
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+ // We expect v2 of the app was installed, but rollback has not
+ // been enabled.
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // TODO: See if there is a way to remove this race condition
+ // between when the app is installed and when the rollback
+ // would be made available.
+ Thread.sleep(1000);
+
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
+ * Test that you cannot enable rollback for a non-module package when
+ * holding the MANAGE_ROLLBACKS permission.
+ */
+ @Test
+ public void testNonModuleEnableRollback() throws Exception {
+ try {
+ RollbackTestUtils.adoptShellPermissionIdentity(
+ Manifest.permission.INSTALL_PACKAGES,
+ Manifest.permission.DELETE_PACKAGES,
+ Manifest.permission.MANAGE_ROLLBACKS);
+
+ RollbackTestUtils.uninstall(TEST_APP_A);
+ RollbackTestUtils.install("RollbackTestAppAv1.apk", /* enableRollback */ false);
+ assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ RollbackTestUtils.install("RollbackTestAppAv2.apk", /* enableRollback */ true);
+
+ // We expect v2 of the app was installed, but rollback has not
+ // been enabled because the test app is not a module.
+ assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
+
+ // TODO: See if there is a way to remove this race condition
+ // between when the app is installed and when the rollback
+ // would be made available.
+ Thread.sleep(1000);
+
+ RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
+ } finally {
+ RollbackTestUtils.dropShellPermissionIdentity();
+ }
+ }
+
+ /**
* Test rollback of multi-package installs is implemented.
*/
@Test
@@ -701,7 +766,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
// Prep installation of the test apps.
@@ -761,6 +826,7 @@
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS,
+ Manifest.permission.TEST_MANAGE_ROLLBACKS,
Manifest.permission.KILL_BACKGROUND_PROCESSES,
Manifest.permission.RESTART_PACKAGES);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -790,34 +856,14 @@
rm.getAvailableRollbacks(), TEST_APP_B);
assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
- BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
+ // Register rollback committed receiver
+ RollbackBroadcastReceiver rollbackReceiver = new RollbackBroadcastReceiver();
- IntentFilter crashCountFilter = new IntentFilter();
- crashCountFilter.addAction("com.android.tests.rollback.CRASH");
- crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
+ // Crash TEST_APP_A PackageWatchdog#TRIGGER_FAILURE_COUNT times to trigger rollback
+ crashCountReceiver = RollbackTestUtils.sendCrashBroadcast(context, TEST_APP_A, 5);
- crashCountReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- try {
- // Sleep long enough for packagewatchdog to be notified of crash
- Thread.sleep(1000);
- // Kill app and close AppErrorDialog
- ActivityManager am = context.getSystemService(ActivityManager.class);
- am.killBackgroundProcesses(TEST_APP_A);
- // Allow another package launch
- crashQueue.put(intent.getIntExtra("count", 0));
- } catch (InterruptedException e) {
- fail("Failed to communicate with test app");
- }
- }
- };
- context.registerReceiver(crashCountReceiver, crashCountFilter);
-
- // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
- do {
- RollbackTestUtils.launchPackage(TEST_APP_A);
- } while(crashQueue.take() < 5);
+ // Verify we received a broadcast for the rollback.
+ rollbackReceiver.take();
// TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index 9aed074..81629aa 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -47,6 +48,7 @@
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.SynchronousQueue;
/**
* Utilities to facilitate testing rollbacks.
@@ -187,7 +189,7 @@
}
/** Launches {@code packageName} with {@link Intent#ACTION_MAIN}. */
- static void launchPackage(String packageName)
+ private static void launchPackage(String packageName)
throws InterruptedException, IOException {
Context context = InstrumentationRegistry.getContext();
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -488,4 +490,39 @@
}
return null;
}
+
+ /**
+ * Send broadcast to crash {@code packageName} {@code count} times. If {@code count} is at least
+ * {@link PackageWatchdog#TRIGGER_FAILURE_COUNT}, watchdog crash detection will be triggered.
+ */
+ static BroadcastReceiver sendCrashBroadcast(Context context, String packageName, int count)
+ throws InterruptedException, IOException {
+ BlockingQueue<Integer> crashQueue = new SynchronousQueue<>();
+ IntentFilter crashCountFilter = new IntentFilter();
+ crashCountFilter.addAction("com.android.tests.rollback.CRASH");
+ crashCountFilter.addCategory(Intent.CATEGORY_DEFAULT);
+
+ BroadcastReceiver crashCountReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ try {
+ // Sleep long enough for packagewatchdog to be notified of crash
+ Thread.sleep(1000);
+ // Kill app and close AppErrorDialog
+ ActivityManager am = context.getSystemService(ActivityManager.class);
+ am.killBackgroundProcesses(packageName);
+ // Allow another package launch
+ crashQueue.put(intent.getIntExtra("count", 0));
+ } catch (InterruptedException e) {
+ fail("Failed to communicate with test app");
+ }
+ }
+ };
+ context.registerReceiver(crashCountReceiver, crashCountFilter);
+
+ do {
+ launchPackage(packageName);
+ } while(crashQueue.take() < count);
+ return crashCountReceiver;
+ }
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 047451b..7e711c2 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -63,7 +63,7 @@
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
Manifest.permission.DELETE_PACKAGES,
- Manifest.permission.MANAGE_ROLLBACKS);
+ Manifest.permission.TEST_MANAGE_ROLLBACKS);
}
/**
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 2539c0f..c62d85e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -13,7 +13,6 @@
"mockito-target-minus-junit4",
"platform-test-annotations",
"services.core",
- "services.ipmemorystore",
"services.net",
],
libs: [
diff --git a/tests/net/java/android/net/DnsPacketTest.java b/tests/net/java/android/net/DnsPacketTest.java
index 9ede2b8..975abf4 100644
--- a/tests/net/java/android/net/DnsPacketTest.java
+++ b/tests/net/java/android/net/DnsPacketTest.java
@@ -69,7 +69,7 @@
try {
new TestDnsPacket(null);
fail("Exception not thrown for null byte array");
- } catch (DnsPacket.ParseException e) {
+ } catch (ParseException e) {
}
}
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 57ecc8f..18c6768 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -16,6 +16,9 @@
package android.net;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+
import android.content.Context;
import androidx.test.filters.SmallTest;
@@ -33,13 +36,25 @@
@Mock
Context mMockContext;
@Mock
+ NetworkStackClient mNetworkStackClient;
+ @Mock
IIpMemoryStore mMockService;
IpMemoryStore mStore;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mStore = new IpMemoryStore(mMockContext, mMockService);
+ doAnswer(invocation -> {
+ ((IIpMemoryStoreCallbacks) invocation.getArgument(0))
+ .onIpMemoryStoreFetched(mMockService);
+ return null;
+ }).when(mNetworkStackClient).fetchIpMemoryStore(any());
+ mStore = new IpMemoryStore(mMockContext) {
+ @Override
+ protected NetworkStackClient getNetworkStackClient() {
+ return mNetworkStackClient;
+ }
+ };
}
@Test
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index 1f2dd27..372ffcd 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -21,12 +21,9 @@
import static org.junit.Assert.fail;
import android.net.SocketKeepalive.InvalidPacketException;
-import android.net.TcpKeepalivePacketData.TcpSocketInfo;
import com.android.internal.util.TestUtils;
-import libcore.net.InetAddressUtils;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -37,14 +34,14 @@
@RunWith(JUnit4.class)
public final class TcpKeepalivePacketDataTest {
+ private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
+ private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
@Before
public void setUp() {}
@Test
- public void testV4TcpKeepalivePacket() {
- final InetAddress srcAddr = InetAddressUtils.parseNumericAddress("192.168.0.1");
- final InetAddress dstAddr = InetAddressUtils.parseNumericAddress("192.168.0.10");
+ public void testV4TcpKeepalivePacket() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int seq = 0x11111111;
@@ -52,20 +49,28 @@
final int wnd = 8000;
final int wndScale = 2;
TcpKeepalivePacketData resultData = null;
- TcpSocketInfo testInfo = new TcpSocketInfo(
- srcAddr, srcPort, dstAddr, dstPort, seq, ack, wnd, wndScale);
+ final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
+ testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
+ testInfo.srcPort = srcPort;
+ testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
+ testInfo.dstPort = dstPort;
+ testInfo.seq = seq;
+ testInfo.ack = ack;
+ testInfo.rcvWnd = wnd;
+ testInfo.rcvWndScale = wndScale;
try {
resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
} catch (InvalidPacketException e) {
fail("InvalidPacketException: " + e);
}
- assertEquals(testInfo.srcAddress, resultData.srcAddress);
- assertEquals(testInfo.dstAddress, resultData.dstAddress);
+ assertEquals(InetAddress.getByAddress(testInfo.srcAddress), resultData.srcAddress);
+ assertEquals(InetAddress.getByAddress(testInfo.dstAddress), resultData.dstAddress);
assertEquals(testInfo.srcPort, resultData.srcPort);
assertEquals(testInfo.dstPort, resultData.dstPort);
assertEquals(testInfo.seq, resultData.tcpSeq);
assertEquals(testInfo.ack, resultData.tcpAck);
+ assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
TestUtils.assertParcelingIsLossless(resultData, TcpKeepalivePacketData.CREATOR);
@@ -78,11 +83,11 @@
byte[] ip = new byte[4];
buf = ByteBuffer.wrap(packet, 12, 4);
buf.get(ip);
- assertArrayEquals(ip, srcAddr.getAddress());
+ assertArrayEquals(ip, IPV4_KEEPALIVE_SRC_ADDR);
// Destination IP address.
buf = ByteBuffer.wrap(packet, 16, 4);
buf.get(ip);
- assertArrayEquals(ip, dstAddr.getAddress());
+ assertArrayEquals(ip, IPV4_KEEPALIVE_DST_ADDR);
buf = ByteBuffer.wrap(packet, 20, 12);
// Source port.
@@ -102,25 +107,32 @@
@Test
public void testParcel() throws Exception {
- final InetAddress srcAddr = InetAddresses.parseNumericAddress("192.168.0.1");
- final InetAddress dstAddr = InetAddresses.parseNumericAddress("192.168.0.10");
final int srcPort = 1234;
final int dstPort = 4321;
final int sequence = 0x11111111;
final int ack = 0x22222222;
final int wnd = 48_000;
final int wndScale = 2;
+ final TcpKeepalivePacketDataParcelable testInfo = new TcpKeepalivePacketDataParcelable();
+ testInfo.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
+ testInfo.srcPort = srcPort;
+ testInfo.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
+ testInfo.dstPort = dstPort;
+ testInfo.seq = sequence;
+ testInfo.ack = ack;
+ testInfo.rcvWnd = wnd;
+ testInfo.rcvWndScale = wndScale;
TcpKeepalivePacketData testData = null;
TcpKeepalivePacketDataParcelable resultData = null;
- TcpSocketInfo testInfo = new TcpSocketInfo(
- srcAddr, srcPort, dstAddr, dstPort, sequence, ack, wnd, wndScale);
testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
resultData = testData.toStableParcelable();
- assertArrayEquals(resultData.srcAddress, srcAddr.getAddress());
- assertArrayEquals(resultData.dstAddress, dstAddr.getAddress());
+ assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
+ assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
assertEquals(resultData.srcPort, srcPort);
assertEquals(resultData.dstPort, dstPort);
assertEquals(resultData.seq, sequence);
assertEquals(resultData.ack, ack);
+ assertEquals(resultData.rcvWnd, wnd);
+ assertEquals(resultData.rcvWndScale, wndScale);
}
}
diff --git a/tests/net/java/android/net/apf/ApfCapabilitiesTest.java b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
new file mode 100644
index 0000000..75752c3
--- /dev/null
+++ b/tests/net/java/android/net/apf/ApfCapabilitiesTest.java
@@ -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.
+ */
+
+package android.net.apf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.net.shared.ParcelableTestUtil;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.TestUtils;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApfCapabilitiesTest {
+ @Test
+ public void testParcelUnparcel() {
+ final ApfCapabilities caps = new ApfCapabilities(123, 456, 789);
+ ParcelableTestUtil.assertFieldCountEquals(3, ApfCapabilities.class);
+
+ TestUtils.assertParcelingIsLossless(caps, ApfCapabilities.CREATOR);
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(new ApfCapabilities(1, 2, 3), new ApfCapabilities(1, 2, 3));
+ assertNotEquals(new ApfCapabilities(2, 2, 3), new ApfCapabilities(1, 2, 3));
+ assertNotEquals(new ApfCapabilities(1, 3, 3), new ApfCapabilities(1, 2, 3));
+ assertNotEquals(new ApfCapabilities(1, 2, 4), new ApfCapabilities(1, 2, 3));
+ }
+}
diff --git a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java b/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
deleted file mode 100644
index 2d0e03d..0000000
--- a/tests/net/java/android/net/shared/LinkPropertiesParcelableUtilTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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 android.net.shared;
-
-import static android.net.shared.LinkPropertiesParcelableUtil.fromStableParcelable;
-import static android.net.shared.LinkPropertiesParcelableUtil.toStableParcelable;
-import static android.net.shared.ParcelableTestUtil.assertFieldCountEquals;
-
-import static org.junit.Assert.assertEquals;
-
-import android.net.InetAddresses;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.ProxyInfo;
-import android.net.RouteInfo;
-import android.net.Uri;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-/**
- * Tests for {@link LinkPropertiesParcelableUtil}
- */
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LinkPropertiesParcelableUtilTest {
- private LinkProperties mLinkProperties;
-
- private static final String TEST_LINKPROPS_IFACE = "TEST_IFACE";
-
- @Before
- public void setUp() {
- mLinkProperties = new LinkProperties();
- mLinkProperties.setInterfaceName(TEST_LINKPROPS_IFACE);
- mLinkProperties.setLinkAddresses(Arrays.asList(
- new LinkAddress(InetAddresses.parseNumericAddress("192.168.0.42"), 16),
- new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::7"), 42)));
- mLinkProperties.setDnsServers(Arrays.asList(
- InetAddresses.parseNumericAddress("2001:db8::42"),
- InetAddresses.parseNumericAddress("192.168.1.1")
- ));
- mLinkProperties.setValidatedPrivateDnsServers(Arrays.asList(
- InetAddresses.parseNumericAddress("2001:db8::43"),
- InetAddresses.parseNumericAddress("192.168.42.43")
- ));
- mLinkProperties.setPcscfServers(Arrays.asList(
- InetAddresses.parseNumericAddress("2001:db8::47"),
- InetAddresses.parseNumericAddress("192.168.42.47")
- ));
- mLinkProperties.setUsePrivateDns(true);
- mLinkProperties.setPrivateDnsServerName("test.example.com");
- mLinkProperties.setDomains("test1.example.com,test2.example.com");
- mLinkProperties.addRoute(new RouteInfo(
- new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::44"), 45),
- InetAddresses.parseNumericAddress("2001:db8::45"),
- TEST_LINKPROPS_IFACE,
- RouteInfo.RTN_UNICAST
- ));
- mLinkProperties.addRoute(new RouteInfo(
- new IpPrefix(InetAddresses.parseNumericAddress("192.168.44.45"), 16),
- InetAddresses.parseNumericAddress("192.168.45.1"),
- TEST_LINKPROPS_IFACE,
- RouteInfo.RTN_THROW
- ));
- mLinkProperties.setHttpProxy(new ProxyInfo("test3.example.com", 8000,
- "excl1.example.com,excl2.example.com"));
- mLinkProperties.setMtu(5000);
- mLinkProperties.setTcpBufferSizes("1,2,3,4,5,6");
- mLinkProperties.setNat64Prefix(
- new IpPrefix(InetAddresses.parseNumericAddress("2001:db8::48"), 96));
-
- // Verify that this test does not miss any new field added later.
- // If any added field is not included in LinkProperties#equals, assertLinkPropertiesEquals
- // must also be updated.
- assertFieldCountEquals(14, LinkProperties.class);
- }
-
- @Test
- public void testParcelUnparcel() {
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullInterface() {
- mLinkProperties.setInterfaceName(null);
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullPrivateDnsServer() {
- mLinkProperties.setPrivateDnsServerName(null);
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullDomains() {
- mLinkProperties.setDomains(null);
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullProxy() {
- mLinkProperties.setHttpProxy(null);
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullTcpBufferSizes() {
- mLinkProperties.setTcpBufferSizes(null);
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_EmptyLinkAddresses() {
- mLinkProperties.setLinkAddresses(Collections.emptyList());
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_EmptyDnses() {
- mLinkProperties.setDnsServers(Collections.emptyList());
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_EmptyValidatedPrivateDnses() {
- mLinkProperties.setValidatedPrivateDnsServers(Collections.emptyList());
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_EmptyRoutes() {
- for (RouteInfo r : mLinkProperties.getAllRoutes()) {
- mLinkProperties.removeRoute(r);
- }
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_PacFileProxyInfo() {
- mLinkProperties.setHttpProxy(new ProxyInfo(Uri.parse("http://pacfile.example.com")));
- doParcelUnparcelTest();
- }
-
- @Test
- public void testParcelUnparcel_NullNat64Prefix() {
- mLinkProperties.setNat64Prefix(null);
- doParcelUnparcelTest();
- }
-
- private void doParcelUnparcelTest() {
- final LinkProperties unparceled = fromStableParcelable(toStableParcelable(mLinkProperties));
- assertLinkPropertiesEquals(mLinkProperties, unparceled);
- }
-
- private static void assertLinkPropertiesEquals(LinkProperties expected, LinkProperties actual) {
- assertEquals(expected, actual);
-
- // Equality on stacked links is not tested as they should not be passed to processes using
- // LinkPropertiesParcelable.
- }
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 0633322..9dfe436 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -60,7 +60,6 @@
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-import static android.net.shared.NetworkParcelableUtil.fromStableParcelable;
import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static com.android.internal.util.TestUtils.waitForIdleLooper;
@@ -125,7 +124,6 @@
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
-import android.net.NetworkParcelable;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStackClient;
@@ -497,13 +495,12 @@
try {
doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyAcceptPartialConnectivity();
+ doAnswer(validateAnswer).when(mNetworkMonitor).setAcceptPartialConnectivity();
} catch (RemoteException e) {
fail(e.getMessage());
}
- final ArgumentCaptor<NetworkParcelable> nmNetworkCaptor =
- ArgumentCaptor.forClass(NetworkParcelable.class);
+ final ArgumentCaptor<Network> nmNetworkCaptor = ArgumentCaptor.forClass(Network.class);
final ArgumentCaptor<INetworkMonitorCallbacks> nmCbCaptor =
ArgumentCaptor.forClass(INetworkMonitorCallbacks.class);
doNothing().when(mNetworkStack).makeNetworkMonitor(
@@ -543,8 +540,7 @@
}
};
- assertEquals(
- mNetworkAgent.netId, fromStableParcelable(nmNetworkCaptor.getValue()).netId);
+ assertEquals(mNetworkAgent.netId, nmNetworkCaptor.getValue().netId);
mNmCallbacks = nmCbCaptor.getValue();
try {
@@ -2554,7 +2550,7 @@
verifyActiveNetwork(TRANSPORT_CELLULAR);
}
- // TODO: deflake and re-enable
+ // TODO(b/128426024): deflake and re-enable
// @Test
public void testPartialConnectivity() {
// Register network callback.
@@ -2589,7 +2585,7 @@
waitForIdle();
try {
verify(mWiFiNetworkAgent.mNetworkMonitor,
- timeout(TIMEOUT_MS).times(1)).notifyAcceptPartialConnectivity();
+ timeout(TIMEOUT_MS).times(1)).setAcceptPartialConnectivity();
} catch (RemoteException e) {
fail(e.getMessage());
}
@@ -2645,7 +2641,7 @@
waitForIdle();
try {
verify(mWiFiNetworkAgent.mNetworkMonitor,
- timeout(TIMEOUT_MS).times(1)).notifyAcceptPartialConnectivity();
+ timeout(TIMEOUT_MS).times(1)).setAcceptPartialConnectivity();
} catch (RemoteException e) {
fail(e.getMessage());
}
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index 6fb3225..968b307 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -23,11 +24,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
import android.net.LinkAddress;
-import android.net.LocalServerSocket;
-import android.net.LocalSocket;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.IBinder;
@@ -43,12 +44,11 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.io.IOException;
-import java.io.OutputStream;
-
/**
* Tests for {@link NetworkManagementService}.
*/
@@ -56,16 +56,16 @@
@SmallTest
public class NetworkManagementServiceTest {
- private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest";
private NetworkManagementService mNMService;
- private LocalServerSocket mServerSocket;
- private LocalSocket mSocket;
- private OutputStream mOutputStream;
@Mock private Context mContext;
@Mock private IBatteryStats.Stub mBatteryStatsService;
@Mock private INetd.Stub mNetdService;
+ @NonNull
+ @Captor
+ private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
+
private final SystemServices mServices = new SystemServices() {
@Override
public IBinder getService(String name) {
@@ -88,32 +88,15 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
-
- // Set up a sheltered test environment.
- mServerSocket = new LocalServerSocket(SOCKET_NAME);
-
+ doNothing().when(mNetdService)
+ .registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
// Start the service and wait until it connects to our socket.
- mNMService = NetworkManagementService.create(mContext, SOCKET_NAME, mServices);
- mSocket = mServerSocket.accept();
- mOutputStream = mSocket.getOutputStream();
+ mNMService = NetworkManagementService.create(mContext, mServices);
}
@After
public void tearDown() throws Exception {
mNMService.shutdown();
- // Once NetworkManagementService#shutdown() actually does something and shutdowns
- // the underlying NativeDaemonConnector, the block below should be uncommented.
- // if (mOutputStream != null) mOutputStream.close();
- // if (mSocket != null) mSocket.close();
- // if (mServerSocket != null) mServerSocket.close();
- }
-
- /**
- * Sends a message on the netd socket and gives the events some time to make it back.
- */
- private void sendMessage(String message) throws IOException {
- // Strings are null-terminated, so add "\0" at the end.
- mOutputStream.write((message + "\0").getBytes());
}
private static <T> T expectSoon(T mock) {
@@ -131,125 +114,78 @@
// Forget everything that happened to the mock so far, so we can explicitly verify
// everything that happens and does not happen to it from now on.
- reset(observer);
- // Now send NetworkManagementService messages and ensure that the observer methods are
- // called. After every valid message we expect a callback soon after; to ensure that
+ INetdUnsolicitedEventListener unsolListener = mUnsolListenerCaptor.getValue();
+ reset(observer);
+ // Now call unsolListener methods and ensure that the observer methods are
+ // called. After every method we expect a callback soon after; to ensure that
// invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end.
/**
* Interface changes.
*/
- sendMessage("600 Iface added rmnet12");
+ unsolListener.onInterfaceAdded("rmnet12");
expectSoon(observer).interfaceAdded("rmnet12");
- sendMessage("600 Iface removed eth1");
+ unsolListener.onInterfaceRemoved("eth1");
expectSoon(observer).interfaceRemoved("eth1");
- sendMessage("607 Iface removed eth1");
- // Invalid code.
-
- sendMessage("600 Iface borked lo down");
- // Invalid event.
-
- sendMessage("600 Iface changed clat4 up again");
- // Extra tokens.
-
- sendMessage("600 Iface changed clat4 up");
+ unsolListener.onInterfaceChanged("clat4", true);
expectSoon(observer).interfaceStatusChanged("clat4", true);
- sendMessage("600 Iface linkstate rmnet0 down");
+ unsolListener.onInterfaceLinkStateChanged("rmnet0", false);
expectSoon(observer).interfaceLinkStateChanged("rmnet0", false);
- sendMessage("600 IFACE linkstate clat4 up");
- // Invalid group.
-
/**
* Bandwidth control events.
*/
- sendMessage("601 limit alert data rmnet_usb0");
+ unsolListener.onQuotaLimitReached("data", "rmnet_usb0");
expectSoon(observer).limitReached("data", "rmnet_usb0");
- sendMessage("601 invalid alert data rmnet0");
- // Invalid group.
-
- sendMessage("601 limit increased data rmnet0");
- // Invalid event.
-
-
/**
* Interface class activity.
*/
-
- sendMessage("613 IfaceClass active 1 1234 10012");
+ unsolListener.onInterfaceClassActivityChanged(true, 1, 1234, 0);
expectSoon(observer).interfaceClassDataActivityChanged("1", true, 1234);
- sendMessage("613 IfaceClass idle 9 5678");
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 5678, 0);
expectSoon(observer).interfaceClassDataActivityChanged("9", false, 5678);
- sendMessage("613 IfaceClass reallyactive 9 4321");
+ unsolListener.onInterfaceClassActivityChanged(false, 9, 4321, 0);
expectSoon(observer).interfaceClassDataActivityChanged("9", false, 4321);
- sendMessage("613 InterfaceClass reallyactive 1");
- // Invalid group.
-
-
/**
* IP address changes.
*/
- sendMessage("614 Address updated fe80::1/64 wlan0 128 253");
+ unsolListener.onInterfaceAddressUpdated("fe80::1/64", "wlan0", 128, 253);
expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253));
- // There is no "added", so we take this as "removed".
- sendMessage("614 Address added fe80::1/64 wlan0 128 253");
+ unsolListener.onInterfaceAddressRemoved("fe80::1/64", "wlan0", 128, 253);
expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253));
- sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0");
+ unsolListener.onInterfaceAddressRemoved("2001:db8::1/64", "wlan0", 1, 0);
expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0));
- sendMessage("614 Address removed 2001:db8::1/64 wlan0 1");
- // Not enough arguments.
-
- sendMessage("666 Address removed 2001:db8::1/64 wlan0 1 0");
- // Invalid code.
-
-
/**
* DNS information broadcasts.
*/
- sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1");
+ unsolListener.onInterfaceDnsServerInfo("rmnet_usb0", 3600, new String[]{"2001:db8::1"});
expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600,
new String[]{"2001:db8::1"});
- sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2");
+ unsolListener.onInterfaceDnsServerInfo("wlan0", 14400,
+ new String[]{"2001:db8::1", "2001:db8::2"});
expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400,
new String[]{"2001:db8::1", "2001:db8::2"});
// We don't check for negative lifetimes, only for parse errors.
- sendMessage("615 DnsInfo servers wlan0 -3600 ::1");
+ unsolListener.onInterfaceDnsServerInfo("wlan0", -3600, new String[]{"::1"});
expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600,
new String[]{"::1"});
- sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1");
- // Non-numeric lifetime.
-
- sendMessage("615 DnsInfo servers wlan0 2001:db8::1");
- // Missing lifetime.
-
- sendMessage("615 DnsInfo servers wlan0 3600");
- // No servers.
-
- sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2");
- // Non-numeric lifetime.
-
- sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2");
- // Invalid tokens.
-
- sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1");
- // Invalid code.
-
// No syntax checking on the addresses.
- sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,");
+ unsolListener.onInterfaceDnsServerInfo("wlan0", 600,
+ new String[]{"", "::", "", "foo", "::1"});
expectSoon(observer).interfaceDnsServerInfo("wlan0", 600,
new String[]{"", "::", "", "foo", "::1"});
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 830c928..9b4f49c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -101,6 +101,7 @@
@After
public void tearDown() throws Exception {
RecurrenceRule.sClock = sOriginalClock;
+ NetworkTemplate.resetForceAllNetworkTypes();
}
private void setClock(Instant instant) {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 598448b..bce526d 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -19,6 +19,7 @@
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -41,6 +42,7 @@
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.net.TrafficStats.UID_REMOVED;
@@ -132,6 +134,8 @@
private static final String TEST_IFACE = "test0";
private static final String TEST_IFACE2 = "test1";
+ private static final String TUN_IFACE = "test_nss_tun0";
+
private static final long TEST_START = 1194220800000L;
private static final String IMSI_1 = "310004";
@@ -145,10 +149,12 @@
private static final int UID_RED = 1001;
private static final int UID_BLUE = 1002;
private static final int UID_GREEN = 1003;
-
+ private static final int UID_VPN = 1004;
private static final Network WIFI_NETWORK = new Network(100);
private static final Network MOBILE_NETWORK = new Network(101);
+ private static final Network VPN_NETWORK = new Network(102);
+
private static final Network[] NETWORKS_WIFI = new Network[]{ WIFI_NETWORK };
private static final Network[] NETWORKS_MOBILE = new Network[]{ MOBILE_NETWORK };
@@ -914,7 +920,113 @@
assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0);
assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0);
assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0);
+ }
+ @Test
+ public void vpnWithOneUnderlyingIface() throws Exception {
+ // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+ expectDefaultSettings();
+ NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(
+ new Network[] {WIFI_NETWORK, VPN_NETWORK},
+ vpnInfos,
+ networkStates,
+ getActiveIface(networkStates));
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // 500 bytes (50 packets) were sent/received by UID_BLUE over VPN.
+ // VPN sent/received 1650 bytes (150 packets) over WiFi.
+ // Of 1650 bytes over WiFi, expect 1000 bytes attributed to UID_RED, 500 bytes attributed to
+ // UID_BLUE, and 150 bytes attributed to UID_VPN for both rx/tx traffic.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+ .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 500L, 50L, 500L, 50L, 1L)
+ .addValues(
+ TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1650L, 150L, 1650L, 150L, 2L));
+
+ forcePollAndWaitForIdle();
+
+ assertUidTotal(sTemplateWifi, UID_RED, 1000L, 100L, 1000L, 100L, 1);
+ assertUidTotal(sTemplateWifi, UID_BLUE, 500L, 50L, 500L, 50L, 1);
+ assertUidTotal(sTemplateWifi, UID_VPN, 150L, 0L, 150L, 0L, 2);
+ }
+
+ @Test
+ public void vpnWithOneUnderlyingIface_withCompression() throws Exception {
+ // WiFi network is connected and VPN is using WiFi (which has TEST_IFACE).
+ expectDefaultSettings();
+ NetworkState[] networkStates = new NetworkState[] {buildWifiState(), buildVpnState()};
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(
+ new Network[] {WIFI_NETWORK, VPN_NETWORK},
+ vpnInfos,
+ networkStates,
+ getActiveIface(networkStates));
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // 3000 bytes (300 packets) were sent/received by UID_BLUE over VPN.
+ // VPN sent/received 1000 bytes (100 packets) over WiFi.
+ // Of 1000 bytes over WiFi, expect 250 bytes attributed UID_RED and 750 bytes to UID_BLUE,
+ // with nothing attributed to UID_VPN for both rx/tx traffic.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3)
+ .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+ .addValues(TUN_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 3000L, 300L, 3000L, 300L, 1L)
+ .addValues(
+ TEST_IFACE, UID_VPN, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 0L));
+
+ forcePollAndWaitForIdle();
+
+ assertUidTotal(sTemplateWifi, UID_RED, 250L, 25L, 250L, 25L, 0);
+ assertUidTotal(sTemplateWifi, UID_BLUE, 750L, 75L, 750L, 75L, 0);
+ assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+ }
+
+ @Test
+ public void vpnWithIncorrectUnderlyingIface() throws Exception {
+ // WiFi and Cell networks are connected and VPN is using Cell (which has TEST_IFACE2),
+ // but has declared only WiFi (TEST_IFACE) in its underlying network set.
+ expectDefaultSettings();
+ NetworkState[] networkStates =
+ new NetworkState[] {
+ buildWifiState(), buildMobile4gState(TEST_IFACE2), buildVpnState()
+ };
+ VpnInfo[] vpnInfos = new VpnInfo[] {createVpnInfo(TEST_IFACE)};
+ expectNetworkStatsUidDetail(buildEmptyStats());
+ expectBandwidthControlCheck();
+
+ mService.forceUpdateIfaces(
+ new Network[] {WIFI_NETWORK, VPN_NETWORK},
+ vpnInfos,
+ networkStates,
+ getActiveIface(networkStates));
+ // create some traffic (assume 10 bytes of MTU for VPN interface and 1 byte encryption
+ // overhead per packet):
+ // 1000 bytes (100 packets) were sent/received by UID_RED over VPN.
+ // VPN sent/received 1100 bytes (100 packets) over Cell.
+ // Of 1100 bytes over Cell, expect all of it attributed to UID_VPN for both rx/tx traffic.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2)
+ .addValues(TUN_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1000L, 100L, 1000L, 100L, 1L)
+ .addValues(
+ TEST_IFACE2, UID_VPN, SET_DEFAULT, TAG_NONE, 1100L, 100L, 1100L, 100L, 1L));
+
+ forcePollAndWaitForIdle();
+
+ assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(sTemplateWifi, UID_VPN, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(buildTemplateMobileWildcard(), UID_RED, 0L, 0L, 0L, 0L, 0);
+ assertUidTotal(buildTemplateMobileWildcard(), UID_VPN, 1100L, 100L, 1100L, 100L, 1);
}
@Test
@@ -1262,6 +1374,22 @@
return new NetworkStats(getElapsedRealtime(), 0);
}
+ private static NetworkState buildVpnState() {
+ final NetworkInfo info = new NetworkInfo(TYPE_VPN, 0, null, null);
+ info.setDetailedState(DetailedState.CONNECTED, null, null);
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(TUN_IFACE);
+ return new NetworkState(info, prop, new NetworkCapabilities(), VPN_NETWORK, null, null);
+ }
+
+ private static VpnInfo createVpnInfo(String underlyingIface) {
+ VpnInfo info = new VpnInfo();
+ info.ownerUid = UID_VPN;
+ info.vpnIface = TUN_IFACE;
+ info.primaryUnderlyingIface = underlyingIface;
+ return info;
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 8bef221..aca2be1 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -198,3 +198,22 @@
static_libs: ["libaapt2"],
defaults: ["aapt2_defaults"],
}
+
+// ==========================================================
+// Dist the protos
+// ==========================================================
+genrule {
+ name: "aapt2-protos",
+ tools: [":soong_zip"],
+ srcs: [
+ "Configuration.proto",
+ "Resources.proto",
+ ],
+ out: ["aapt2-protos.zip"],
+ cmd: "mkdir $(genDir)/protos && " +
+ "cp $(in) $(genDir)/protos && " +
+ "$(location :soong_zip) -o $(out) -C $(genDir)/protos -D $(genDir)/protos",
+ dist: {
+ targets: ["sdk_repo"],
+ },
+}
diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h
index 5cf056e..7ded9bc 100644
--- a/tools/aapt2/cmd/Dump.h
+++ b/tools/aapt2/cmd/Dump.h
@@ -32,6 +32,7 @@
public:
explicit DumpApkCommand(const std::string&& name, text::Printer* printer, IDiagnostics* diag)
: Command(name), printer_(printer), diag_(diag) {
+ SetDescription("Dump information about an APK or APC.");
}
text::Printer* GetPrinter() {
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index e937517..a24e0d2f 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -58,7 +58,7 @@
// valid. This is because un-mangled references are mangled, then looked up at resolution
// time. Also, when linking, we convert references with no package name to use the compilation
// package name.
- error |= !DoMerge(src, table, package.get(), false /*mangle*/, overlay, allow_new);
+ error |= !DoMerge(src, package.get(), false /*mangle*/, overlay, allow_new);
}
}
return !error;
@@ -78,7 +78,7 @@
bool mangle = package_name != context_->GetCompilationPackage();
merged_packages_.insert(package->name);
- error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
+ error |= !DoMerge(src, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
}
return !error;
}
@@ -213,9 +213,8 @@
return collision_result;
}
-bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table,
- ResourceTablePackage* src_package, bool mangle_package, bool overlay,
- bool allow_new_resources) {
+bool TableMerger::DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
+ bool overlay, bool allow_new_resources) {
bool error = false;
for (auto& src_type : src_package->types) {
@@ -337,8 +336,7 @@
->FindOrCreateValue(file_desc.config, {})
->value = std::move(file_ref);
- return DoMerge(file->GetSource(), &table, pkg, false /*mangle*/, overlay /*overlay*/,
- true /*allow_new*/);
+ return DoMerge(file->GetSource(), pkg, false /*mangle*/, overlay /*overlay*/, true /*allow_new*/);
}
} // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 24c5e13..51305cf 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -85,8 +85,8 @@
bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
- bool DoMerge(const Source& src, ResourceTable* src_table, ResourceTablePackage* src_package,
- bool mangle_package, bool overlay, bool allow_new_resources);
+ bool DoMerge(const Source& src, ResourceTablePackage* src_package, bool mangle_package,
+ bool overlay, bool allow_new_resources);
std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package,
const FileReference& value);
diff --git a/tools/processors/view_inspector/Android.bp b/tools/processors/view_inspector/Android.bp
index 06ff05e..069e61f 100644
--- a/tools/processors/view_inspector/Android.bp
+++ b/tools/processors/view_inspector/Android.bp
@@ -8,6 +8,7 @@
static_libs: [
"javapoet",
+ "stub-annotations",
],
use_tools_jar: true,
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
index 2690ee8..c833e47 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/AnnotationUtils.java
@@ -16,6 +16,8 @@
package android.processor.view.inspector;
+import androidx.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -40,7 +42,7 @@
private final Elements mElementUtils;
private final Types mTypeUtils;
- AnnotationUtils(ProcessingEnvironment processingEnv) {
+ AnnotationUtils(@NonNull ProcessingEnvironment processingEnv) {
mElementUtils = processingEnv.getElementUtils();
mTypeUtils = processingEnv.getTypeUtils();
}
@@ -53,7 +55,8 @@
* @return The mirror of the requested annotation
* @throws ProcessingException If there is not exactly one of the requested annotation.
*/
- AnnotationMirror exactlyOneMirror(String qualifiedName, Element element) {
+ @NonNull
+ AnnotationMirror exactlyOneMirror(@NonNull String qualifiedName, @NonNull Element element) {
final Element targetTypeElment = mElementUtils.getTypeElement(qualifiedName);
final TypeMirror targetType = targetTypeElment.asType();
AnnotationMirror result = null;
@@ -89,7 +92,7 @@
* @param annotationQualifiedName The name of the annotation to check for
* @return True if the annotation is present, false otherwise
*/
- boolean hasAnnotation(Element element, String annotationQualifiedName) {
+ boolean hasAnnotation(@NonNull Element element, @NonNull String annotationQualifiedName) {
final TypeElement namedElement = mElementUtils.getTypeElement(annotationQualifiedName);
if (namedElement != null) {
@@ -118,10 +121,10 @@
* @return A list containing the requested types
*/
<T> List<T> typedArrayValuesByName(
- String propertyName,
- Class<T> valueClass,
- Element element,
- AnnotationMirror annotationMirror) {
+ @NonNull String propertyName,
+ @NonNull Class<T> valueClass,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
return untypedArrayValuesByName(propertyName, element, annotationMirror)
.stream()
.map(annotationValue -> {
@@ -159,10 +162,11 @@
* @param annotationMirror An annotation mirror to search for the property
* @return A list of annotation values, empty list if none found
*/
+ @NonNull
List<AnnotationValue> untypedArrayValuesByName(
- String propertyName,
- Element element,
- AnnotationMirror annotationMirror) {
+ @NonNull String propertyName,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
return typedValueByName(propertyName, List.class, element, annotationMirror)
.map(untypedValues -> {
List<AnnotationValue> typedValues = new ArrayList<>(untypedValues.size());
@@ -195,6 +199,7 @@
* @param <T> The type of the value
* @return An optional containing the typed value of the named property
*/
+ @NonNull
<T> Optional<T> typedValueByName(
String propertyName,
Class<T> valueClass,
@@ -241,10 +246,11 @@
* @return An optional containing the untyped value of the named property
* @see AnnotationValue#getValue()
*/
+ @NonNull
Optional<Object> untypedValueByName(
- String propertyName,
- Element element,
- AnnotationMirror annotationMirror) {
+ @NonNull String propertyName,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
return valueByName(propertyName, annotationMirror).map(annotationValue -> {
final Object value = annotationValue.getValue();
@@ -269,7 +275,10 @@
* @param annotationMirror The mirror to search for the property
* @return The value of the property
*/
- Optional<AnnotationValue> valueByName(String propertyName, AnnotationMirror annotationMirror) {
+ @NonNull
+ Optional<AnnotationValue> valueByName(
+ @NonNull String propertyName,
+ @NonNull AnnotationMirror annotationMirror) {
final Map<? extends ExecutableElement, ? extends AnnotationValue> valueMap =
annotationMirror.getElementValues();
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
index 1ad7ada..04710e4 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableClassModel.java
@@ -16,6 +16,9 @@
package android.processor.view.inspector;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import com.squareup.javapoet.ClassName;
import java.util.Collection;
@@ -34,36 +37,28 @@
* testing {@link InspectionCompanionGenerator}.
*/
public final class InspectableClassModel {
- private final ClassName mClassName;
- private final Map<String, Property> mPropertyMap;
- private Optional<String> mNodeName = Optional.empty();
+ private final @NonNull ClassName mClassName;
+ private final @NonNull Map<String, Property> mPropertyMap;
/**
* @param className The name of the modeled class
*/
- public InspectableClassModel(ClassName className) {
+ public InspectableClassModel(@NonNull ClassName className) {
mClassName = className;
mPropertyMap = new HashMap<>();
}
+ @NonNull
public ClassName getClassName() {
return mClassName;
}
- public Optional<String> getNodeName() {
- return mNodeName;
- }
-
- public void setNodeName(Optional<String> nodeName) {
- mNodeName = nodeName;
- }
-
/**
* Add a property to the model, replacing an existing property of the same name.
*
* @param property The property to add or replace
*/
- public void putProperty(Property property) {
+ public void putProperty(@NonNull Property property) {
mPropertyMap.put(property.getName(), property);
}
@@ -73,7 +68,8 @@
* @param name The name of the property
* @return The property or an empty optional
*/
- public Optional<Property> getProperty(String name) {
+ @NonNull
+ public Optional<Property> getProperty(@NonNull String name) {
return Optional.ofNullable(mPropertyMap.get(name));
}
@@ -82,6 +78,7 @@
*
* @return An un-ordered collection of properties
*/
+ @NonNull
public Collection<Property> getAllProperties() {
return mPropertyMap.values();
}
@@ -90,8 +87,8 @@
* Represents a way to access a property, either a getter or a field.
*/
public static final class Accessor {
- private final String mName;
- private final Type mType;
+ private final @NonNull String mName;
+ private final @NonNull Type mType;
/**
* Construct an accessor for a field.
@@ -100,7 +97,8 @@
* @return The new accessor
* @see Type#FIELD
*/
- static Accessor ofField(String name) {
+ @NonNull
+ static Accessor ofField(@NonNull String name) {
return new Accessor(name, Type.FIELD);
}
@@ -111,19 +109,22 @@
* @return The new accessor
* @see Type#GETTER
*/
- static Accessor ofGetter(String name) {
+ @NonNull
+ static Accessor ofGetter(@NonNull String name) {
return new Accessor(name, Type.GETTER);
}
- public Accessor(String name, Type type) {
+ public Accessor(@NonNull String name, @NonNull Type type) {
mName = Objects.requireNonNull(name, "Accessor name must not be null");
mType = Objects.requireNonNull(type, "Accessor type must not be null");
}
+ @NonNull
public String getName() {
return mName;
}
+ @NonNull
public Type getType() {
return mType;
}
@@ -135,6 +136,7 @@
*
* @return A string representing the invocation of this accessor
*/
+ @NonNull
public String invocation() {
switch (mType) {
case FIELD:
@@ -168,15 +170,15 @@
* Model an inspectable property
*/
public static final class Property {
- private final String mName;
- private final Accessor mAccessor;
- private final Type mType;
+ private final @NonNull String mName;
+ private final @NonNull Accessor mAccessor;
+ private final @NonNull Type mType;
private boolean mAttributeIdInferrableFromR = true;
private int mAttributeId = 0;
- private List<IntEnumEntry> mIntEnumEntries;
- private List<IntFlagEntry> mIntFlagEntries;
+ private @Nullable List<IntEnumEntry> mIntEnumEntries;
+ private @Nullable List<IntFlagEntry> mIntFlagEntries;
- public Property(String name, Accessor accessor, Type type) {
+ public Property(@NonNull String name, @NonNull Accessor accessor, @NonNull Type type) {
mName = Objects.requireNonNull(name, "Name must not be null");
mAccessor = Objects.requireNonNull(accessor, "Accessor must not be null");
mType = Objects.requireNonNull(type, "Type must not be null");
@@ -204,14 +206,17 @@
mAttributeIdInferrableFromR = attributeIdInferrableFromR;
}
+ @NonNull
public String getName() {
return mName;
}
+ @NonNull
public Accessor getAccessor() {
return mAccessor;
}
+ @NonNull
public Type getType() {
return mType;
}
@@ -221,6 +226,7 @@
*
* @return A list of mapping entries, empty if absent
*/
+ @NonNull
public List<IntEnumEntry> getIntEnumEntries() {
if (mIntEnumEntries != null) {
return mIntEnumEntries;
@@ -229,7 +235,7 @@
}
}
- public void setIntEnumEntries(List<IntEnumEntry> intEnumEntries) {
+ public void setIntEnumEntries(@NonNull List<IntEnumEntry> intEnumEntries) {
mIntEnumEntries = intEnumEntries;
}
@@ -238,6 +244,7 @@
*
* @return A list of mapping entries, empty if absent
*/
+ @NonNull
public List<IntFlagEntry> getIntFlagEntries() {
if (mIntFlagEntries != null) {
return mIntFlagEntries;
@@ -246,7 +253,7 @@
}
}
- public void setIntFlagEntries(List<IntFlagEntry> intFlagEntries) {
+ public void setIntFlagEntries(@NonNull List<IntFlagEntry> intFlagEntries) {
mIntFlagEntries = intFlagEntries;
}
@@ -321,14 +328,15 @@
* @see android.view.inspector.IntEnumMapping
*/
public static final class IntEnumEntry {
- private final String mName;
+ private final @NonNull String mName;
private final int mValue;
- public IntEnumEntry(String name, int value) {
+ public IntEnumEntry(int value, @NonNull String name) {
mName = Objects.requireNonNull(name, "Name must not be null");
mValue = value;
}
+ @NonNull
public String getName() {
return mName;
}
@@ -344,29 +352,21 @@
* @see android.view.inspector.IntFlagMapping
*/
public static final class IntFlagEntry {
- private final String mName;
+ private final @NonNull String mName;
private final int mTarget;
private final int mMask;
- public IntFlagEntry(String name, int target, int mask) {
+ public IntFlagEntry(int mask, int target, @NonNull String name) {
mName = Objects.requireNonNull(name, "Name must not be null");
mTarget = target;
mMask = mask;
}
- public IntFlagEntry(String name, int target) {
- this(name, target, target);
+ public IntFlagEntry(int target, String name) {
+ this(target, target, name);
}
- /**
- * Determine if this entry has a bitmask.
- *
- * @return True if the bitmask and target are different, false otherwise
- */
- public boolean hasMask() {
- return mTarget != mMask;
- }
-
+ @NonNull
public String getName() {
return mName;
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
deleted file mode 100644
index 46819b2..0000000
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectableNodeNameProcessor.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 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 android.processor.view.inspector;
-
-import java.util.Optional;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-
-/**
- * Process {@code @InspectableNodeName} annotations.
- *
- * @see android.view.inspector.InspectableNodeName
- */
-public final class InspectableNodeNameProcessor implements ModelProcessor {
- private final String mQualifiedName;
- private final ProcessingEnvironment mProcessingEnv;
- private final AnnotationUtils mAnnotationUtils;
-
- /**
- * @param annotationQualifiedName The qualified name of the annotation to process
- * @param processingEnv The processing environment from the parent processor
- */
- public InspectableNodeNameProcessor(
- String annotationQualifiedName,
- ProcessingEnvironment processingEnv) {
- mQualifiedName = annotationQualifiedName;
- mProcessingEnv = processingEnv;
- mAnnotationUtils = new AnnotationUtils(processingEnv);
- }
-
- /**
- * Set the node name on the model if one is supplied.
- *
- * If the model already has a different node name, the node name will not be updated, and
- * the processor will print an error the the messager.
- *
- * @param element The annotated element to operate on
- * @param model The model this element should be merged into
- */
- @Override
- public void process(Element element, InspectableClassModel model) {
- try {
- final AnnotationMirror mirror =
- mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
- final Optional<String> nodeName = mAnnotationUtils
- .typedValueByName("value", String.class, element, mirror);
-
- if (!model.getNodeName().isPresent() || model.getNodeName().equals(nodeName)) {
- model.setNodeName(nodeName);
- } else {
- final String message = String.format(
- "Node name was already set to \"%s\", refusing to change it to \"%s\".",
- model.getNodeName().get(),
- nodeName);
- throw new ProcessingException(message, element, mirror);
- }
- } catch (ProcessingException processingException) {
- processingException.print(mProcessingEnv.getMessager());
- }
- }
-}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
index 20de90d..2bd867c 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectablePropertyProcessor.java
@@ -21,6 +21,8 @@
import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
import android.processor.view.inspector.InspectableClassModel.Property;
+import androidx.annotation.NonNull;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -44,10 +46,10 @@
*
* @see android.view.inspector.InspectableProperty
*/
-public final class InspectablePropertyProcessor implements ModelProcessor {
- private final String mQualifiedName;
- private final ProcessingEnvironment mProcessingEnv;
- private final AnnotationUtils mAnnotationUtils;
+public final class InspectablePropertyProcessor {
+ private final @NonNull String mQualifiedName;
+ private final @NonNull ProcessingEnvironment mProcessingEnv;
+ private final @NonNull AnnotationUtils mAnnotationUtils;
/**
* Regex that matches methods names of the form {@code #getValue()}.
@@ -130,15 +132,14 @@
* @param processingEnv The processing environment from the parent processor
*/
public InspectablePropertyProcessor(
- String annotationQualifiedName,
- ProcessingEnvironment processingEnv) {
+ @NonNull String annotationQualifiedName,
+ @NonNull ProcessingEnvironment processingEnv) {
mQualifiedName = annotationQualifiedName;
mProcessingEnv = processingEnv;
mAnnotationUtils = new AnnotationUtils(processingEnv);
}
- @Override
- public void process(Element element, InspectableClassModel model) {
+ public void process(@NonNull Element element, @NonNull InspectableClassModel model) {
try {
final AnnotationMirror annotation =
mAnnotationUtils.exactlyOneMirror(mQualifiedName, element);
@@ -169,7 +170,10 @@
* @return A property for the getter and annotation
* @throws ProcessingException If the supplied data is invalid and a property cannot be modeled
*/
- private Property buildProperty(Element accessor, AnnotationMirror annotation) {
+ @NonNull
+ private Property buildProperty(
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
final Property property;
final Optional<String> nameFromAnnotation = mAnnotationUtils
.typedValueByName("name", String.class, accessor, annotation);
@@ -227,7 +231,7 @@
* @param element The element to check
* @throws ProcessingException If the element's modifiers are invalid
*/
- private void validateModifiers(Element element) {
+ private void validateModifiers(@NonNull Element element) {
final Set<Modifier> modifiers = element.getModifiers();
if (!modifiers.contains(Modifier.PUBLIC)) {
@@ -256,7 +260,8 @@
* @return An {@link ExecutableElement} that represents a getter method.
* @throws ProcessingException if the element isn't a getter
*/
- private ExecutableElement ensureGetter(Element element) {
+ @NonNull
+ private ExecutableElement ensureGetter(@NonNull Element element) {
if (element.getKind() != ElementKind.METHOD) {
throw new ProcessingException(
String.format("Expected a method, got a %s", element.getKind()),
@@ -300,10 +305,10 @@
* @throws ProcessingException If the property type cannot be resolved or is invalid
* @see android.view.inspector.InspectableProperty#valueType()
*/
+ @NonNull
private Property.Type determinePropertyType(
- Element accessor,
- AnnotationMirror annotation) {
-
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
final String valueType = mAnnotationUtils
.untypedValueByName("valueType", accessor, annotation)
.map(Object::toString)
@@ -437,7 +442,8 @@
* @return The return or field type of the element
* @throws ProcessingException If the element is not a field or a method
*/
- private TypeMirror extractReturnOrFieldType(Element element) {
+ @NonNull
+ private TypeMirror extractReturnOrFieldType(@NonNull Element element) {
switch (element.getKind()) {
case FIELD:
return element.asType();
@@ -460,7 +466,10 @@
* @return The property type returned by the getter
* @throws ProcessingException If the return type is not a primitive or an object
*/
- private Property.Type convertTypeMirrorToPropertyType(TypeMirror typeMirror, Element element) {
+ @NonNull
+ private Property.Type convertTypeMirrorToPropertyType(
+ @NonNull TypeMirror typeMirror,
+ @NonNull Element element) {
switch (unboxType(typeMirror)) {
case BOOLEAN:
return Property.Type.BOOLEAN;
@@ -503,10 +512,10 @@
* @throws ProcessingException If the return type is not an int
*/
private static void requirePackedIntToBeInt(
- String typeName,
- Property.Type returnType,
- Element accessor,
- AnnotationMirror annotation) {
+ @NonNull String typeName,
+ @NonNull Property.Type returnType,
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
if (returnType != Property.Type.INT) {
throw new ProcessingException(
String.format(
@@ -528,7 +537,7 @@
* @param accessor The getter or field to query
* @return True if the getter has a color annotation, false otherwise
*/
- private boolean hasColorAnnotation(Element accessor) {
+ private boolean hasColorAnnotation(@NonNull Element accessor) {
switch (unboxType(extractReturnOrFieldType(accessor))) {
case INT:
for (String name : COLOR_INT_ANNOTATION_NAMES) {
@@ -555,7 +564,7 @@
* @param accessor The getter or field to query
* @return True if the accessor is an integer and has a resource ID annotation, false otherwise
*/
- private boolean hasResourceIdAnnotation(Element accessor) {
+ private boolean hasResourceIdAnnotation(@NonNull Element accessor) {
if (unboxType(extractReturnOrFieldType(accessor)) == TypeKind.INT) {
for (String name : RESOURCE_ID_ANNOTATION_NAMES) {
if (mAnnotationUtils.hasAnnotation(accessor, name)) {
@@ -581,7 +590,8 @@
* @param getter An element representing a getter
* @return A string property name
*/
- private String inferPropertyNameFromGetter(ExecutableElement getter) {
+ @NonNull
+ private String inferPropertyNameFromGetter(@NonNull ExecutableElement getter) {
final String name = getter.getSimpleName().toString();
if (GETTER_GET_PREFIX.matcher(name).find()) {
@@ -597,10 +607,9 @@
* Build a model of an {@code int} enumeration mapping from annotation values.
*
* This method only handles the one-to-one mapping of mirrors of
- * {@link android.view.inspector.InspectableProperty.EnumMap} annotations into
+ * {@link android.view.inspector.InspectableProperty.EnumEntry} annotations into
* {@link IntEnumEntry} objects. Further validation should be handled elsewhere
*
- * @see android.view.inspector.IntEnumMapping
* @see android.view.inspector.InspectableProperty#enumMapping()
* @param accessor The accessor of the property, used for exceptions
* @param annotation The {@link android.view.inspector.InspectableProperty} annotation to
@@ -608,9 +617,10 @@
* @return A list of int enum entries, in the order specified in source
* @throws ProcessingException if mapping doesn't exist or is invalid
*/
+ @NonNull
private List<IntEnumEntry> processEnumMapping(
- Element accessor,
- AnnotationMirror annotation) {
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
List<AnnotationMirror> enumAnnotations = mAnnotationUtils.typedArrayValuesByName(
"enumMapping", AnnotationMirror.class, accessor, annotation);
List<IntEnumEntry> enumEntries = new ArrayList<>(enumAnnotations.size());
@@ -623,23 +633,19 @@
for (AnnotationMirror enumAnnotation : enumAnnotations) {
final String name = mAnnotationUtils.typedValueByName(
"name", String.class, accessor, enumAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Name is required for @EnumMap",
- accessor,
- enumAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Name is required for @EnumEntry",
+ accessor,
+ enumAnnotation));
final int value = mAnnotationUtils.typedValueByName(
"value", Integer.class, accessor, enumAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Value is required for @EnumMap",
- accessor,
- enumAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Value is required for @EnumEntry",
+ accessor,
+ enumAnnotation));
- enumEntries.add(new IntEnumEntry(name, value));
+ enumEntries.add(new IntEnumEntry(value, name));
}
return enumEntries;
@@ -649,7 +655,7 @@
* Build a model of an {@code int} flag mapping from annotation values.
*
* This method only handles the one-to-one mapping of mirrors of
- * {@link android.view.inspector.InspectableProperty.FlagMap} annotations into
+ * {@link android.view.inspector.InspectableProperty.FlagEntry} annotations into
* {@link IntFlagEntry} objects. Further validation should be handled elsewhere
*
* @see android.view.inspector.IntFlagMapping
@@ -660,9 +666,10 @@
* @return A list of int flags entries, in the order specified in source
* @throws ProcessingException if mapping doesn't exist or is invalid
*/
+ @NonNull
private List<IntFlagEntry> processFlagMapping(
- Element accessor,
- AnnotationMirror annotation) {
+ @NonNull Element accessor,
+ @NonNull AnnotationMirror annotation) {
List<AnnotationMirror> flagAnnotations = mAnnotationUtils.typedArrayValuesByName(
"flagMapping", AnnotationMirror.class, accessor, annotation);
List<IntFlagEntry> flagEntries = new ArrayList<>(flagAnnotations.size());
@@ -675,29 +682,25 @@
for (AnnotationMirror flagAnnotation : flagAnnotations) {
final String name = mAnnotationUtils.typedValueByName(
"name", String.class, accessor, flagAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Name is required for @FlagMap",
- accessor,
- flagAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Name is required for @FlagEntry",
+ accessor,
+ flagAnnotation));
final int target = mAnnotationUtils.typedValueByName(
"target", Integer.class, accessor, flagAnnotation)
- .orElseThrow(() -> {
- throw new ProcessingException(
- "Target is required for @FlagMap",
- accessor,
- flagAnnotation);
- });
+ .orElseThrow(() -> new ProcessingException(
+ "Target is required for @FlagEntry",
+ accessor,
+ flagAnnotation));
final Optional<Integer> mask = mAnnotationUtils.typedValueByName(
"mask", Integer.class, accessor, flagAnnotation);
if (mask.isPresent()) {
- flagEntries.add(new IntFlagEntry(name, target, mask.get()));
+ flagEntries.add(new IntFlagEntry(mask.get(), target, name));
} else {
- flagEntries.add(new IntFlagEntry(name, target));
+ flagEntries.add(new IntFlagEntry(target, name));
}
}
@@ -710,7 +713,7 @@
* @param type The type mirror to check
* @return True if the type is a boolean
*/
- private boolean isBoolean(TypeMirror type) {
+ private boolean isBoolean(@NonNull TypeMirror type) {
if (type.getKind() == TypeKind.DECLARED) {
return mProcessingEnv.getTypeUtils().unboxedType(type).getKind() == TypeKind.BOOLEAN;
} else {
@@ -724,7 +727,8 @@
* @param typeMirror The type mirror to unbox
* @return The same type mirror, or an unboxed primitive version
*/
- private TypeKind unboxType(TypeMirror typeMirror) {
+ @NonNull
+ private TypeKind unboxType(@NonNull TypeMirror typeMirror) {
final TypeKind typeKind = typeMirror.getKind();
if (typeKind.isPrimitive()) {
@@ -746,7 +750,7 @@
* @param typeMirror The type mirror to test
* @return True if it represents a subclass of color, false otherwise
*/
- private boolean isColorType(TypeMirror typeMirror) {
+ private boolean isColorType(@NonNull TypeMirror typeMirror) {
final TypeElement colorType = mProcessingEnv
.getElementUtils()
.getTypeElement("android.graphics.Color");
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 6f6c1aa..6e38c24 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -16,11 +16,12 @@
package android.processor.view.inspector;
-
import android.processor.view.inspector.InspectableClassModel.IntEnumEntry;
import android.processor.view.inspector.InspectableClassModel.IntFlagEntry;
import android.processor.view.inspector.InspectableClassModel.Property;
+import androidx.annotation.NonNull;
+
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
@@ -34,9 +35,11 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.NoSuchElementException;
-import java.util.Optional;
+import java.util.stream.Collectors;
import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;
@@ -45,8 +48,8 @@
* Generates a source file defining a {@link android.view.inspector.InspectionCompanion}.
*/
public final class InspectionCompanionGenerator {
- private final Filer mFiler;
- private final Class mRequestingClass;
+ private final @NonNull Filer mFiler;
+ private final @NonNull Class mRequestingClass;
/**
* The class name for {@code R.java}.
@@ -72,10 +75,9 @@
"android.view.inspector", "PropertyReader");
/**
- * The class name of {@link android.view.inspector.IntEnumMapping}.
+ * The class name of {@link android.util.SparseArray}.
*/
- private static final ClassName INT_ENUM_MAPPING = ClassName.get(
- "android.view.inspector", "IntEnumMapping");
+ private static final ClassName SPARSE_ARRAY = ClassName.get("android.util", "SparseArray");
/**
* The class name of {@link android.view.inspector.IntFlagMapping}.
@@ -84,17 +86,6 @@
"android.view.inspector", "IntFlagMapping");
/**
- * The {@code mPropertiesMapped} field.
- */
- private static final FieldSpec M_PROPERTIES_MAPPED = FieldSpec
- .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE)
- .initializer("false")
- .addJavadoc(
- "Set by {@link #mapProperties($T)} once properties have been mapped.\n",
- PROPERTY_MAPPER)
- .build();
-
- /**
* The suffix of the generated class name after the class's binary name.
*/
private static final String GENERATED_CLASS_SUFFIX = "$InspectionCompanion";
@@ -110,7 +101,7 @@
* @param filer A filer to write the generated source to
* @param requestingClass A class object representing the class that invoked the generator
*/
- public InspectionCompanionGenerator(Filer filer, Class requestingClass) {
+ public InspectionCompanionGenerator(@NonNull Filer filer, @NonNull Class requestingClass) {
mFiler = filer;
mRequestingClass = requestingClass;
}
@@ -121,7 +112,7 @@
* @param model The model to generated
* @throws IOException From the Filer
*/
- public void generate(InspectableClassModel model) throws IOException {
+ public void generate(@NonNull InspectableClassModel model) throws IOException {
generateFile(model).writeTo(mFiler);
}
@@ -133,7 +124,8 @@
* @param model The model to generate from
* @return A generated file of an {@link android.view.inspector.InspectionCompanion}
*/
- JavaFile generateFile(InspectableClassModel model) {
+ @NonNull
+ JavaFile generateFile(@NonNull InspectableClassModel model) {
return JavaFile
.builder(model.getClassName().packageName(), generateTypeSpec(model))
.indent(" ")
@@ -147,8 +139,12 @@
* @param model The model to generate from
* @return A TypeSpec of the inspection companion
*/
- private TypeSpec generateTypeSpec(InspectableClassModel model) {
- final List<PropertyIdField> propertyIdFields = generatePropertyIdFields(model);
+ @NonNull
+ private TypeSpec generateTypeSpec(@NonNull InspectableClassModel model) {
+ final List<Property> properties = new ArrayList<>(model.getAllProperties());
+ properties.sort(Comparator.comparing(Property::getName));
+
+ final Map<Property, FieldSpec> fields = generateIdFieldSpecs(properties);
TypeSpec.Builder builder = TypeSpec
.classBuilder(generateClassName(model))
@@ -158,238 +154,298 @@
.addJavadoc("Inspection companion for {@link $T}.\n\n", model.getClassName())
.addJavadoc("Generated by {@link $T}\n", getClass())
.addJavadoc("on behalf of {@link $T}.\n", mRequestingClass)
- .addField(M_PROPERTIES_MAPPED);
-
- for (PropertyIdField propertyIdField : propertyIdFields) {
- builder.addField(propertyIdField.mFieldSpec);
- }
-
- builder.addMethod(generateMapProperties(propertyIdFields))
- .addMethod(generateReadProperties(model, propertyIdFields));
-
- generateGetNodeName(model).ifPresent(builder::addMethod);
+ .addField(FieldSpec
+ .builder(TypeName.BOOLEAN, "mPropertiesMapped", Modifier.PRIVATE)
+ .initializer("false")
+ .addJavadoc("Guards against reading properties before mapping them.\n")
+ .build())
+ .addFields(properties.stream().map(fields::get).collect(Collectors.toList()))
+ .addMethod(generateMapProperties(properties, fields))
+ .addMethod(generateReadProperties(properties, fields, model.getClassName()));
return builder.build();
}
/**
- * Build a list of {@link PropertyIdField}'s for a model.
+ * Map properties to fields to store the mapping IDs in the generated inspection companion.
*
- * To insure idempotency of the generated code, this method sorts the list of properties
- * alphabetically by name.
- *
- * A {@link NameAllocator} is used to ensure that the field names are valid Java identifiers,
- * and it prevents overlaps in names by suffixing them as needed.
- *
- * @param model The model to get properties from
- * @return A list of properties and fields
+ * @param properties A list of property models
+ * @return A map of properties to their {@link FieldSpec}
*/
- private List<PropertyIdField> generatePropertyIdFields(InspectableClassModel model) {
- final NameAllocator nameAllocator = new NameAllocator();
- final List<Property> sortedProperties = new ArrayList<>(model.getAllProperties());
- final List<PropertyIdField> propertyIdFields = new ArrayList<>(sortedProperties.size());
+ @NonNull
+ private Map<Property, FieldSpec> generateIdFieldSpecs(@NonNull List<Property> properties) {
+ final Map<Property, FieldSpec> fields = new HashMap<>();
+ final NameAllocator fieldNames = new NameAllocator();
+ fieldNames.newName("mPropertiesMapped");
- sortedProperties.sort(Comparator.comparing(Property::getName));
-
- for (Property property : sortedProperties) {
- // Format a property to a member field name like "someProperty" -> "mSomePropertyId"
- final String memberName = String.format(
+ for (Property property : properties) {
+ final String memberName = fieldNames.newName(String.format(
"m%s%sId",
property.getName().substring(0, 1).toUpperCase(),
- property.getName().substring(1));
- final FieldSpec fieldSpec = FieldSpec
- .builder(TypeName.INT, nameAllocator.newName(memberName), Modifier.PRIVATE)
- .addJavadoc("Property ID of {@code $L}.\n", property.getName())
- .build();
+ property.getName().substring(1)));
- propertyIdFields.add(new PropertyIdField(fieldSpec, property));
+ fields.put(property, FieldSpec
+ .builder(TypeName.INT, memberName, Modifier.PRIVATE)
+ .addJavadoc("Property ID of {@code $L}.\n", property.getName())
+ .build());
}
- return propertyIdFields;
+ return fields;
}
/**
- * Generate a method definition for
- * {@link android.view.inspector.InspectionCompanion#getNodeName()}, if needed.
- *
- * If {@link InspectableClassModel#getNodeName()} is empty, This method returns an empty
- * optional, otherwise, it generates a simple method that returns the string value of the
- * node name.
- *
- * @param model The model to generate from
- * @return The method definition or an empty Optional
- */
- private Optional<MethodSpec> generateGetNodeName(InspectableClassModel model) {
- return model.getNodeName().map(nodeName -> MethodSpec.methodBuilder("getNodeName")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .returns(String.class)
- .addStatement("return $S", nodeName)
- .build());
- }
-
- /**
- * Generate a method definition for
+ * Generates an implementation of
* {@link android.view.inspector.InspectionCompanion#mapProperties(
* android.view.inspector.PropertyMapper)}.
*
- * @param propertyIdFields A list of properties to map to ID fields
- * @return The method definition
+ * Example:
+ * <pre>
+ * @Override
+ * public void mapProperties(PropertyMapper propertyMapper) {
+ * mValueId = propertyMapper.mapInt("value", R.attr.value);
+ * mPropertiesMapped = true;
+ * }
+ * </pre>
+ *
+ * @param properties A sorted list of property models
+ * @param fields A map of properties to their ID field specs
+ * @return A method definition
*/
- private MethodSpec generateMapProperties(List<PropertyIdField> propertyIdFields) {
+ @NonNull
+ private MethodSpec generateMapProperties(
+ @NonNull List<Property> properties,
+ @NonNull Map<Property, FieldSpec> fields) {
+ final NameAllocator mappingVariables = new NameAllocator();
+
final MethodSpec.Builder builder = MethodSpec.methodBuilder("mapProperties")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.addParameter(PROPERTY_MAPPER, "propertyMapper");
- propertyIdFields.forEach(p -> builder.addStatement(generatePropertyMapperInvocation(p)));
- builder.addStatement("$N = true", M_PROPERTIES_MAPPED);
+ // Reserve existing names
+ mappingVariables.newName("mPropertiesMapped");
+ mappingVariables.newName("propertyMapper");
+ properties.forEach(p -> mappingVariables.newName(fields.get(p).name));
- return builder.build();
- }
-
- /**
- * Generate a method definition for
- * {@link android.view.inspector.InspectionCompanion#readProperties(
- * Object, android.view.inspector.PropertyReader)}.
- *
- * @param model The model to generate from
- * @param propertyIdFields A list of properties and ID fields to read from
- * @return The method definition
- */
- private MethodSpec generateReadProperties(
- InspectableClassModel model,
- List<PropertyIdField> propertyIdFields) {
- final MethodSpec.Builder builder = MethodSpec.methodBuilder("readProperties")
- .addAnnotation(Override.class)
- .addModifiers(Modifier.PUBLIC)
- .addParameter(model.getClassName(), "node")
- .addParameter(PROPERTY_READER, "propertyReader")
- .addCode(generatePropertyMapInitializationCheck());
-
- for (PropertyIdField propertyIdField : propertyIdFields) {
- builder.addStatement(
- "propertyReader.read$L($N, node.$L)",
- methodSuffixForPropertyType(propertyIdField.mProperty.getType()),
- propertyIdField.mFieldSpec,
- propertyIdField.mProperty.getAccessor().invocation());
- }
-
- return builder.build();
- }
-
- /**
- * Generate a statement maps a property with a {@link android.view.inspector.PropertyMapper}.
- *
- * @param propertyIdField The property model and ID field to generate from
- * @return A statement that invokes property mapper method
- */
- private CodeBlock generatePropertyMapperInvocation(PropertyIdField propertyIdField) {
- final CodeBlock.Builder builder = CodeBlock.builder();
- final Property property = propertyIdField.mProperty;
- final FieldSpec fieldSpec = propertyIdField.mFieldSpec;
-
- builder.add(
- "$N = propertyMapper.map$L($S,$W",
- fieldSpec,
- methodSuffixForPropertyType(property.getType()),
- property.getName());
-
- if (property.isAttributeIdInferrableFromR()) {
- builder.add("$T.attr.$L", R_CLASS_NAME, property.getName());
- } else {
- if (property.getAttributeId() == ID_NULL) {
- builder.add("$L", ID_NULL);
- } else {
- builder.add("$L", hexLiteral(property.getAttributeId()));
+ for (Property property : properties) {
+ final FieldSpec field = fields.get(property);
+ switch (property.getType()) {
+ case INT_ENUM:
+ builder.addCode(generateIntEnumPropertyMapperInvocation(
+ property,
+ field,
+ mappingVariables.newName(property.getName() + "EnumMapping")));
+ break;
+ case INT_FLAG:
+ builder.addCode(generateIntFlagPropertyMapperInvocation(
+ property,
+ field,
+ mappingVariables.newName(property.getName() + "FlagMapping")));
+ break;
+ default:
+ builder.addCode(generateSimplePropertyMapperInvocation(property, field));
}
}
- switch (property.getType()) {
- case INT_ENUM:
- builder.add(",$W");
- builder.add(generateIntEnumMappingBuilder(property.getIntEnumEntries()));
- break;
- case INT_FLAG:
- builder.add(",$W");
- builder.add(generateIntFlagMappingBuilder(property.getIntFlagEntries()));
- break;
- }
+ builder.addStatement("mPropertiesMapped = true");
- return builder.add(")").build();
+ return builder.build();
}
/**
- * Generate a check that throws
- * {@link android.view.inspector.InspectionCompanion.UninitializedPropertyMapException}
- * if the properties haven't been initialized.
+ * Generate a {@link android.view.inspector.PropertyMapper} invocation.
*
+ * Example:
* <pre>
- * if (!mPropertiesMapped) {
- * throw new InspectionCompanion.UninitializedPropertyMapException();
- * }
+ * mValueId = propertyMapper.mapInt("value", R.attr.value);
* </pre>
*
- * @return A codeblock containing the property map initialization check
+ * @param property A property model to map
+ * @param field The property ID field for the property
+ * @return A code block containing a statement
*/
- private CodeBlock generatePropertyMapInitializationCheck() {
- return CodeBlock.builder()
- .beginControlFlow("if (!$N)", M_PROPERTIES_MAPPED)
+ @NonNull
+ private CodeBlock generateSimplePropertyMapperInvocation(
+ @NonNull Property property,
+ @NonNull FieldSpec field) {
+ return CodeBlock
+ .builder()
.addStatement(
- "throw new $T()",
- INSPECTION_COMPANION.nestedClass("UninitializedPropertyMapException"))
- .endControlFlow()
+ "$N = propertyMapper.map$L($S, $L)",
+ field,
+ methodSuffixForPropertyType(property.getType()),
+ property.getName(),
+ generateAttributeId(property))
.build();
}
/**
- * Generate an invocation of {@link android.view.inspector.IntEnumMapping.Builder}.
+ * Generate a {@link android.view.inspector.PropertyMapper} invocation for an int enum.
*
+ * Example:
* <pre>
- * new IntEnumMapping.Builder()
- * .addValue("ONE", 1)
- * .build()
+ * final SparseArray<String> valueEnumMapping = new SparseArray<>();
+ * valueEnumMapping.put(1, "ONE");
+ * valueEnumMapping.put(2, "TWO");
+ * mValueId = propertyMapper.mapIntEnum("value", R.attr.value, valueEnumMapping::get);
* </pre>
*
- * @return A codeblock containing the an int enum mapping builder
+ * @param property A property model to map
+ * @param field The property ID field for the property
+ * @param variable The name of a local variable to use to store the mapping in
+ * @return A code block containing a series of statements
*/
- private CodeBlock generateIntEnumMappingBuilder(List<IntEnumEntry> intEnumEntries) {
- final ArrayList<IntEnumEntry> sortedEntries = new ArrayList<>(intEnumEntries);
- sortedEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
+ @NonNull
+ private CodeBlock generateIntEnumPropertyMapperInvocation(
+ @NonNull Property property,
+ @NonNull FieldSpec field,
+ @NonNull String variable) {
+ final CodeBlock.Builder builder = CodeBlock.builder();
- final CodeBlock.Builder builder = CodeBlock.builder()
- .add("new $T()$>", INT_ENUM_MAPPING.nestedClass("Builder"));
+ final List<IntEnumEntry> enumEntries = property.getIntEnumEntries();
+ enumEntries.sort(Comparator.comparing(IntEnumEntry::getValue));
- for (IntEnumEntry entry : sortedEntries) {
- builder.add("\n.addValue($S, $L)", entry.getName(), entry.getValue());
+ builder.addStatement(
+ "final $1T<$2T> $3N = new $1T<>()",
+ SPARSE_ARRAY,
+ String.class,
+ variable);
+
+ for (IntEnumEntry enumEntry : enumEntries) {
+ builder.addStatement(
+ "$N.put($L, $S)",
+ variable,
+ enumEntry.getValue(),
+ enumEntry.getName());
}
- return builder.add("\n.build()$<").build();
+ builder.addStatement(
+ "$N = propertyMapper.mapIntEnum($S, $L, $N::get)",
+ field,
+ property.getName(),
+ generateAttributeId(property),
+ variable);
+
+ return builder.build();
}
- private CodeBlock generateIntFlagMappingBuilder(List<IntFlagEntry> intFlagEntries) {
- final ArrayList<IntFlagEntry> sortedEntries = new ArrayList<>(intFlagEntries);
- sortedEntries.sort(Comparator.comparing(IntFlagEntry::getName));
+ /**
+ * Generate a {@link android.view.inspector.PropertyMapper} invocation for an int flag.
+ *
+ * Example:
+ * <pre>
+ * final IntFlagMapping valueFlagMapping = new IntFlagMapping();
+ * valueFlagMapping.add(0x00000003, 0x00000001, "ONE");
+ * valueFlagMapping.add(0x00000003, 0x00000002, "TWO");
+ * mValueId = propertyMapper.mapIntFlag("value", R.attr.value, valueFlagMapping::get);
+ * </pre>
+ *
+ * @param property A property model to map
+ * @param field The property ID field for the property
+ * @param variable The name of a local variable to use to store the mapping in
+ * @return A code block containing a series of statements
+ */
+ @NonNull
+ private CodeBlock generateIntFlagPropertyMapperInvocation(
+ @NonNull Property property,
+ @NonNull FieldSpec field,
+ @NonNull String variable) {
+ final CodeBlock.Builder builder = CodeBlock.builder();
- final CodeBlock.Builder builder = CodeBlock.builder()
- .add("new $T()$>", INT_FLAG_MAPPING.nestedClass("Builder"));
+ final List<IntFlagEntry> flagEntries = property.getIntFlagEntries();
+ flagEntries.sort(Comparator.comparing(IntFlagEntry::getName));
- for (IntFlagEntry entry : sortedEntries) {
- if (entry.hasMask()) {
- builder.add(
- "\n.addFlag($S, $L, $L)",
- entry.getName(),
- hexLiteral(entry.getTarget()),
- hexLiteral(entry.getMask()));
- } else {
- builder.add(
- "\n.addFlag($S, $L)",
- entry.getName(),
- hexLiteral(entry.getTarget()));
- }
+ builder.addStatement(
+ "final $1T $2N = new $1T()",
+ INT_FLAG_MAPPING,
+ variable);
+
+ for (IntFlagEntry flagEntry : flagEntries) {
+ builder.addStatement(
+ "$N.add($L, $L, $S)",
+ variable,
+ hexLiteral(flagEntry.getMask()),
+ hexLiteral(flagEntry.getTarget()),
+ flagEntry.getName());
}
- return builder.add("\n.build()$<").build();
+ builder.addStatement(
+ "$N = propertyMapper.mapIntFlag($S, $L, $N::get)",
+ field,
+ property.getName(),
+ generateAttributeId(property),
+ variable);
+
+ return builder.build();
+ }
+
+ /**
+ * Generate a literal attribute ID or reference to {@link android.R.attr}.
+ *
+ * Example: {@code R.attr.value} or {@code 0xdecafbad}.
+ *
+ * @param property A property model
+ * @return A code block containing the attribute ID
+ */
+ @NonNull
+ private CodeBlock generateAttributeId(@NonNull Property property) {
+ if (property.isAttributeIdInferrableFromR()) {
+ return CodeBlock.of("$T.attr.$L", R_CLASS_NAME, property.getName());
+ } else {
+ if (property.getAttributeId() == ID_NULL) {
+ return CodeBlock.of("$L", ID_NULL);
+ } else {
+ return CodeBlock.of("$L", hexLiteral(property.getAttributeId()));
+ }
+ }
+ }
+
+ /**
+ * Generate an implementation of
+ * {@link android.view.inspector.InspectionCompanion#readProperties(Object,
+ * android.view.inspector.PropertyReader)}.
+ *
+ * Example:
+ * <pre>
+ * @Override
+ * public void readProperties(MyNode node, PropertyReader propertyReader) {
+ * if (!mPropertiesMapped) {
+ * throw new InspectionCompanion.UninitializedPropertyMapException();
+ * }
+ * propertyReader.readInt(mValueId, node.getValue());
+ * }
+ * </pre>
+ *
+ * @param properties An ordered list of property models
+ * @param fields A map from properties to their field specs
+ * @param nodeClass The class of the node, used for the parameter type
+ * @return A method definition
+ */
+ @NonNull
+ private MethodSpec generateReadProperties(
+ @NonNull List<Property> properties,
+ @NonNull Map<Property, FieldSpec> fields,
+ @NonNull ClassName nodeClass) {
+ final MethodSpec.Builder builder = MethodSpec.methodBuilder("readProperties")
+ .addAnnotation(Override.class)
+ .addModifiers(Modifier.PUBLIC)
+ .addParameter(nodeClass, "node")
+ .addParameter(PROPERTY_READER, "propertyReader")
+ .beginControlFlow("if (!mPropertiesMapped)")
+ .addStatement(
+ "throw new $T()",
+ INSPECTION_COMPANION.nestedClass("UninitializedPropertyMapException"))
+ .endControlFlow();
+
+ for (Property property : properties) {
+ builder.addStatement(
+ "propertyReader.read$L($N, node.$L)",
+ methodSuffixForPropertyType(property.getType()),
+ fields.get(property),
+ property.getAccessor().invocation());
+ }
+
+ return builder.build();
}
/**
@@ -397,14 +453,15 @@
*
* The generated class is added to the same package as the source class. If the class in the
* model is a nested class, the nested class names are joined with {@code "$"}. The suffix
- * {@code "$$InspectionCompanion"} is always added the the generated name. E.g.: For modeled
+ * {@code "$InspectionCompanion"} is always added to the generated name. E.g.: For modeled
* class {@code com.example.Outer.Inner}, the generated class name will be
- * {@code com.example.Outer$Inner$$InspectionCompanion}.
+ * {@code com.example.Outer$Inner$InspectionCompanion}.
*
* @param model The model to generate from
* @return A class name for the generated inspection companion class
*/
- private static ClassName generateClassName(InspectableClassModel model) {
+ @NonNull
+ private static ClassName generateClassName(@NonNull InspectableClassModel model) {
final ClassName className = model.getClassName();
return ClassName.get(
@@ -418,7 +475,8 @@
* @param type The requested property type
* @return A method suffix
*/
- private static String methodSuffixForPropertyType(Property.Type type) {
+ @NonNull
+ private static String methodSuffixForPropertyType(@NonNull Property.Type type) {
switch (type) {
case BOOLEAN:
return "Boolean";
@@ -453,20 +511,14 @@
}
}
+ /**
+ * Format an int as an 8 digit hex literal
+ *
+ * @param value The value to format
+ * @return A string representation of the hex literal
+ */
+ @NonNull
private static String hexLiteral(int value) {
return String.format("0x%08x", value);
}
-
- /**
- * Value class that holds a {@link Property} and a {@link FieldSpec} for that property.
- */
- private static final class PropertyIdField {
- private final FieldSpec mFieldSpec;
- private final Property mProperty;
-
- private PropertyIdField(FieldSpec fieldSpec, Property property) {
- mFieldSpec = fieldSpec;
- mProperty = property;
- }
- }
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
deleted file mode 100644
index 6f52260..0000000
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ModelProcessor.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 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 android.processor.view.inspector;
-
-import javax.lang.model.element.Element;
-
-/**
- * An interface for annotation processors that operate on a single element and a class model.
- */
-public interface ModelProcessor {
- /**
- * Process the supplied element, mutating the model as needed.
- *
- * @param element The annotated element to operate on
- * @param model The model this element should be merged into
- */
- void process(Element element, InspectableClassModel model);
-}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index fd142c6..80d3727 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -18,6 +18,8 @@
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.annotation.NonNull;
+
import com.squareup.javapoet.ClassName;
import java.io.IOException;
@@ -36,25 +38,18 @@
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.ElementFilter;
-
/**
* An annotation processor for the platform inspectable annotations.
*
- * It mostly delegates to {@link ModelProcessor} and {@link InspectionCompanionGenerator}. This
- * modular architecture allows the core generation code to be reused for comparable annotations
- * outside the platform, such as in AndroidX.
+ * It mostly delegates to {@link InspectablePropertyProcessor} and
+ * {@link InspectionCompanionGenerator}. This modular architecture allows the core generation code
+ * to be reused for comparable annotations outside the platform.
*
- * @see android.view.inspector.InspectableNodeName
* @see android.view.inspector.InspectableProperty
*/
-@SupportedAnnotationTypes({
- PlatformInspectableProcessor.NODE_NAME_QUALIFIED_NAME,
- PlatformInspectableProcessor.PROPERTY_QUALIFIED_NAME
-})
+@SupportedAnnotationTypes({PlatformInspectableProcessor.ANNOTATION_QUALIFIED_NAME})
public final class PlatformInspectableProcessor extends AbstractProcessor {
- static final String NODE_NAME_QUALIFIED_NAME =
- "android.view.inspector.InspectableNodeName";
- static final String PROPERTY_QUALIFIED_NAME =
+ static final String ANNOTATION_QUALIFIED_NAME =
"android.view.inspector.InspectableProperty";
@Override
@@ -63,22 +58,14 @@
}
@Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ public boolean process(
+ @NonNull Set<? extends TypeElement> annotations,
+ @NonNull RoundEnvironment roundEnv) {
final Map<String, InspectableClassModel> modelMap = new HashMap<>();
for (TypeElement annotation : annotations) {
- if (annotation.getQualifiedName().contentEquals(NODE_NAME_QUALIFIED_NAME)) {
- runModelProcessor(
- roundEnv.getElementsAnnotatedWith(annotation),
- new InspectableNodeNameProcessor(NODE_NAME_QUALIFIED_NAME, processingEnv),
- modelMap);
-
- } else if (annotation.getQualifiedName().contentEquals(PROPERTY_QUALIFIED_NAME)) {
- runModelProcessor(
- roundEnv.getElementsAnnotatedWith(annotation),
- new InspectablePropertyProcessor(PROPERTY_QUALIFIED_NAME, processingEnv),
- modelMap);
-
+ if (annotation.getQualifiedName().contentEquals(ANNOTATION_QUALIFIED_NAME)) {
+ processProperties(roundEnv.getElementsAnnotatedWith(annotation), modelMap);
} else {
fail("Unexpected annotation type", annotation);
}
@@ -102,16 +89,17 @@
}
/**
- * Run a {@link ModelProcessor} for a set of elements
+ * Runs {@link PlatformInspectableProcessor} on a set of annotated elements.
*
- * @param elements Elements to process, should be annotated correctly
- * @param processor The processor to use
- * @param modelMap A map of qualified class names to models
+ * @param elements A set of annotated elements to process
+ * @param modelMap A map of qualified class names to class models to update
*/
- private void runModelProcessor(
- Set<? extends Element> elements,
- ModelProcessor processor,
- Map<String, InspectableClassModel> modelMap) {
+ private void processProperties(
+ @NonNull Set<? extends Element> elements,
+ @NonNull Map<String, InspectableClassModel> modelMap) {
+ final InspectablePropertyProcessor processor =
+ new InspectablePropertyProcessor(ANNOTATION_QUALIFIED_NAME, processingEnv);
+
for (Element element : elements) {
final Optional<TypeElement> classElement = enclosingClassElement(element);
@@ -149,7 +137,7 @@
* @param typeElement A type element representing the class to check
* @return f the class contains a class named {@code InspectionCompanion}
*/
- private static boolean hasNestedInspectionCompanion(TypeElement typeElement) {
+ private static boolean hasNestedInspectionCompanion(@NonNull TypeElement typeElement) {
for (TypeElement nestedClass : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
if (nestedClass.getSimpleName().toString().equals("InspectionCompanion")) {
return true;
@@ -167,7 +155,8 @@
* @param element An element to search from
* @return A TypeElement of the nearest enclosing class or an empty optional
*/
- private static Optional<TypeElement> enclosingClassElement(Element element) {
+ @NonNull
+ private static Optional<TypeElement> enclosingClassElement(@NonNull Element element) {
Element cursor = element;
while (cursor != null) {
@@ -186,7 +175,7 @@
*
* @param message Message to print
*/
- private void fail(String message) {
+ private void fail(@NonNull String message) {
processingEnv.getMessager().printMessage(ERROR, message);
}
@@ -196,7 +185,7 @@
* @param message Message to print
* @param element The element that failed
*/
- private void fail(String message, Element element) {
+ private void fail(@NonNull String message, @NonNull Element element) {
processingEnv.getMessager().printMessage(ERROR, message, element);
}
}
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
index b4c6466..7389c24 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/ProcessingException.java
@@ -18,6 +18,9 @@
import static javax.tools.Diagnostic.Kind.ERROR;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
import javax.annotation.processing.Messager;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
@@ -27,27 +30,30 @@
* Internal exception used to signal an error processing an annotation.
*/
final class ProcessingException extends RuntimeException {
- private final Element mElement;
- private final AnnotationMirror mAnnotationMirror;
- private final AnnotationValue mAnnotationValue;
+ private final @Nullable Element mElement;
+ private final @Nullable AnnotationMirror mAnnotationMirror;
+ private final @Nullable AnnotationValue mAnnotationValue;
- ProcessingException(String message) {
+ ProcessingException(@NonNull String message) {
this(message, null, null, null);
}
- ProcessingException(String message, Element element) {
+ ProcessingException(@NonNull String message, @NonNull Element element) {
this(message, element, null, null);
}
- ProcessingException(String message, Element element, AnnotationMirror annotationMirror) {
+ ProcessingException(
+ @NonNull String message,
+ @NonNull Element element,
+ @NonNull AnnotationMirror annotationMirror) {
this(message, element, annotationMirror, null);
}
ProcessingException(
- String message,
- Element element,
- AnnotationMirror annotationMirror,
- AnnotationValue annotationValue) {
+ @NonNull String message,
+ @Nullable Element element,
+ @Nullable AnnotationMirror annotationMirror,
+ @Nullable AnnotationValue annotationValue) {
super(message);
mElement = element;
mAnnotationMirror = annotationMirror;
@@ -59,7 +65,7 @@
*
* @param messager A Messager to print to
*/
- void print(Messager messager) {
+ void print(@NonNull Messager messager) {
if (mElement != null) {
if (mAnnotationMirror != null) {
if (mAnnotationValue != null) {
diff --git a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
index 4eed504..c6e6018 100644
--- a/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
+++ b/tools/processors/view_inspector/test/java/android/processor/view/inspector/InspectionCompanionGeneratorTest.java
@@ -36,7 +36,6 @@
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
-import java.util.Optional;
/**
* Tests for {@link InspectionCompanionGenerator}
@@ -56,12 +55,6 @@
}
@Test
- public void testNodeName() {
- mModel.setNodeName(Optional.of("NodeName"));
- assertGeneratedFileEquals("NodeName");
- }
-
- @Test
public void testNestedClass() {
mModel = new InspectableClassModel(
ClassName.get("com.android.node", "Outer", "Inner"));
@@ -118,9 +111,9 @@
Property.Type.INT_ENUM);
property.setIntEnumEntries(Arrays.asList(
- new IntEnumEntry("THREE", 3),
- new IntEnumEntry("TWO", 2),
- new IntEnumEntry("ONE", 1)));
+ new IntEnumEntry(3, "THREE"),
+ new IntEnumEntry(2, "TWO"),
+ new IntEnumEntry(1, "ONE")));
mModel.putProperty(property);
@@ -136,9 +129,9 @@
property.setAttributeIdInferrableFromR(false);
property.setIntFlagEntries(Arrays.asList(
- new IntFlagEntry("TURBO", 0x1, 0x3),
- new IntFlagEntry("OVERDRIVE", 0x2, 0x3),
- new IntFlagEntry("WARP", 0x4)
+ new IntFlagEntry(0x3, 0x1, "TURBO"),
+ new IntFlagEntry(0x3, 0x2, "OVERDRIVE"),
+ new IntFlagEntry(0x4, "WARP")
));
assertGeneratedFileEquals("IntFlag");
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
index 9a0fe5b..e4a8ba4 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
@@ -14,7 +14,7 @@
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
index b491de1..fa9dbfd 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -1,11 +1,12 @@
package com.android.node;
import android.R;
+import android.util.SparseArray;
import android.view.inspector.InspectionCompanion;
-import android.view.inspector.IntEnumMapping;
import android.view.inspector.PropertyMapper;
import android.view.inspector.PropertyReader;
import java.lang.Override;
+import java.lang.String;
/**
* Inspection companion for {@link TestNode}.
@@ -15,7 +16,7 @@
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
@@ -26,12 +27,11 @@
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty,
- new IntEnumMapping.Builder()
- .addValue("ONE", 1)
- .addValue("TWO", 2)
- .addValue("THREE", 3)
- .build());
+ final SparseArray<String> intEnumPropertyEnumMapping = new SparseArray<>();
+ intEnumPropertyEnumMapping.put(1, "ONE");
+ intEnumPropertyEnumMapping.put(2, "TWO");
+ intEnumPropertyEnumMapping.put(3, "THREE");
+ mIntEnumPropertyId = propertyMapper.mapIntEnum("intEnumProperty", R.attr.intEnumProperty, intEnumPropertyEnumMapping::get);
mPropertiesMapped = true;
}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
index 7d18058..ed3d8ee 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -14,7 +14,7 @@
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
@@ -25,11 +25,11 @@
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, new IntFlagMapping.Builder()
- .addFlag("OVERDRIVE", 0x00000002, 0x00000003)
- .addFlag("TURBO", 0x00000001, 0x00000003)
- .addFlag("WARP", 0x00000004)
- .build());
+ final IntFlagMapping intFlagFlagMapping = new IntFlagMapping();
+ intFlagFlagMapping.add(0x00000003, 0x00000002, "OVERDRIVE");
+ intFlagFlagMapping.add(0x00000003, 0x00000001, "TURBO");
+ intFlagFlagMapping.add(0x00000004, 0x00000004, "WARP");
+ mIntFlagId = propertyMapper.mapIntFlag("intFlag", 0, intFlagFlagMapping::get);
mPropertiesMapped = true;
}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index dc27abb..4514ed9 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -13,7 +13,7 @@
*/
public final class Outer$Inner$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index 738bcd3..563f93df 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -13,7 +13,7 @@
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
deleted file mode 100644
index 82dd66e..0000000
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-package com.android.node;
-
-import android.view.inspector.InspectionCompanion;
-import android.view.inspector.PropertyMapper;
-import android.view.inspector.PropertyReader;
-import java.lang.Override;
-import java.lang.String;
-
-/**
- * Inspection companion for {@link TestNode}.
- *
- * Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
- * on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
- */
-public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
- /**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
- */
- private boolean mPropertiesMapped = false;
-
- @Override
- public void mapProperties(PropertyMapper propertyMapper) {
- mPropertiesMapped = true;
- }
-
- @Override
- public void readProperties(TestNode node, PropertyReader propertyReader) {
- if (!mPropertiesMapped) {
- throw new InspectionCompanion.UninitializedPropertyMapException();
- }
- }
-
- @Override
- public String getNodeName() {
- return "NodeName";
- }
-}
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 08ea696..cb85767 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -14,7 +14,7 @@
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index 3bfa78a..731d410 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -13,7 +13,7 @@
*/
public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
- * Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
+ * Guards against reading properties before mapping them.
*/
private boolean mPropertiesMapped = false;
@@ -24,8 +24,7 @@
@Override
public void mapProperties(PropertyMapper propertyMapper) {
- mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty",
- 0xdecafbad);
+ mSuppliedAttributePropertyId = propertyMapper.mapInt("suppliedAttributeProperty", 0xdecafbad);
mPropertiesMapped = true;
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 7a505a2..950c6f8 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -139,6 +139,8 @@
private X509Certificate[] mClientCertificateChain;
private int mEapMethod = Eap.NONE;
private int mPhase2Method = Phase2.NONE;
+ private boolean mIsAppInstalledDeviceKeyAndCert = false;
+ private boolean mIsAppInstalledCaCert = false;
private static final String TAG = "WifiEnterpriseConfig";
@@ -181,6 +183,8 @@
}
mEapMethod = source.mEapMethod;
mPhase2Method = source.mPhase2Method;
+ mIsAppInstalledDeviceKeyAndCert = source.mIsAppInstalledDeviceKeyAndCert;
+ mIsAppInstalledCaCert = source.mIsAppInstalledCaCert;
}
/**
@@ -224,6 +228,8 @@
ParcelUtil.writeCertificates(dest, mCaCerts);
ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
ParcelUtil.writeCertificates(dest, mClientCertificateChain);
+ dest.writeBoolean(mIsAppInstalledDeviceKeyAndCert);
+ dest.writeBoolean(mIsAppInstalledCaCert);
}
public static final @android.annotation.NonNull Creator<WifiEnterpriseConfig> CREATOR =
@@ -243,6 +249,8 @@
enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
enterpriseConfig.mClientCertificateChain = ParcelUtil.readCertificates(in);
+ enterpriseConfig.mIsAppInstalledDeviceKeyAndCert = in.readBoolean();
+ enterpriseConfig.mIsAppInstalledCaCert = in.readBoolean();
return enterpriseConfig;
}
@@ -652,8 +660,10 @@
public void setCaCertificate(@Nullable X509Certificate cert) {
if (cert != null) {
if (cert.getBasicConstraints() >= 0) {
+ mIsAppInstalledCaCert = true;
mCaCerts = new X509Certificate[] {cert};
} else {
+ mCaCerts = null;
throw new IllegalArgumentException("Not a CA certificate");
}
} else {
@@ -694,10 +704,12 @@
if (certs[i].getBasicConstraints() >= 0) {
newCerts[i] = certs[i];
} else {
+ mCaCerts = null;
throw new IllegalArgumentException("Not a CA certificate");
}
}
mCaCerts = newCerts;
+ mIsAppInstalledCaCert = true;
} else {
mCaCerts = null;
}
@@ -853,6 +865,7 @@
mClientPrivateKey = privateKey;
mClientCertificateChain = newCerts;
+ mIsAppInstalledDeviceKeyAndCert = true;
}
/**
@@ -1147,4 +1160,30 @@
}
return true;
}
+
+ /**
+ * Check if certificate was installed by an app, or manually (not by an app). If true,
+ * certificate and keys will be removed from key storage when this network is removed. If not,
+ * then certificates and keys remain persistent until the user manually removes them.
+ *
+ * @return true if certificate was installed by an app, false if certificate was installed
+ * manually by the user.
+ * @hide
+ */
+ public boolean isAppInstalledDeviceKeyAndCert() {
+ return mIsAppInstalledDeviceKeyAndCert;
+ }
+
+ /**
+ * Check if CA certificate was installed by an app, or manually (not by an app). If true,
+ * CA certificate will be removed from key storage when this network is removed. If not,
+ * then certificates and keys remain persistent until the user manually removes them.
+ *
+ * @return true if CA certificate was installed by an app, false if CA certificate was installed
+ * manually by the user.
+ * @hide
+ */
+ public boolean isAppInstalledCaCert() {
+ return mIsAppInstalledCaCert;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index d38b2f4..06a99e2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -4880,14 +4880,14 @@
/**
* Provide a Wi-Fi usability score information to be recorded (but not acted upon) by the
- * framework. The Wi-Fi usability score is derived from {@link WifiUsabilityStatsListener}
+ * framework. The Wi-Fi usability score is derived from {@link OnWifiUsabilityStatsListener}
* where a score is matched to Wi-Fi usability statistics using the sequence number. The score
* is used to quantify whether Wi-Fi is usable in a future time.
*
* @param seqNum Sequence number of the Wi-Fi usability score.
- * @param score The Wi-Fi usability score.
+ * @param score The Wi-Fi usability score, expected range: [0, 100].
* @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second,
- * expected range: [0, 100].
+ * expected range: [0, 30].
*
* @hide
*/
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 32a7a47..a9c9939 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -403,7 +403,7 @@
* .setWpa3Passphrase("test6789")
* .build()
* final List<WifiNetworkSuggestion> suggestionsList =
- * new ArrayList<WifiNetworkSuggestion> {{
+ * new ArrayList<WifiNetworkSuggestion> {{
* add(suggestion1);
* add(suggestion2);
* add(suggestion3);
diff --git a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
index 51aa93a..01176f2 100644
--- a/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
+++ b/wifi/java/android/net/wifi/WifiUsabilityStatsEntry.java
@@ -20,6 +20,7 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.TelephonyManager.NetworkType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -98,6 +99,10 @@
private final int mProbeMcsRateSinceLastUpdate;
/** Rx link speed at the sample time in Mbps */
private final int mRxLinkSpeedMbps;
+ private final @NetworkType int mCellularDataNetworkType;
+ private final int mCellularSignalStrengthDbm;
+ private final int mCellularSignalStrengthDb;
+ private final boolean mIsSameRegisteredCell;
/** Constructor function {@hide} */
public WifiUsabilityStatsEntry(long timeStampMillis, int rssi, int linkSpeedMbps,
@@ -109,7 +114,10 @@
long totalHotspot2ScanTimeMillis,
long totalCcaBusyFreqTimeMillis, long totalRadioOnFreqTimeMillis, long totalBeaconRx,
@ProbeStatus int probeStatusSinceLastUpdate, int probeElapsedTimeSinceLastUpdateMillis,
- int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps) {
+ int probeMcsRateSinceLastUpdate, int rxLinkSpeedMbps,
+ @NetworkType int cellularDataNetworkType,
+ int cellularSignalStrengthDbm, int cellularSignalStrengthDb,
+ boolean isSameRegisteredCell) {
mTimeStampMillis = timeStampMillis;
mRssi = rssi;
mLinkSpeedMbps = linkSpeedMbps;
@@ -133,6 +141,10 @@
mProbeElapsedTimeSinceLastUpdateMillis = probeElapsedTimeSinceLastUpdateMillis;
mProbeMcsRateSinceLastUpdate = probeMcsRateSinceLastUpdate;
mRxLinkSpeedMbps = rxLinkSpeedMbps;
+ mCellularDataNetworkType = cellularDataNetworkType;
+ mCellularSignalStrengthDbm = cellularSignalStrengthDbm;
+ mCellularSignalStrengthDb = cellularSignalStrengthDb;
+ mIsSameRegisteredCell = isSameRegisteredCell;
}
/** Implement the Parcelable interface */
@@ -165,6 +177,10 @@
dest.writeInt(mProbeElapsedTimeSinceLastUpdateMillis);
dest.writeInt(mProbeMcsRateSinceLastUpdate);
dest.writeInt(mRxLinkSpeedMbps);
+ dest.writeInt(mCellularDataNetworkType);
+ dest.writeInt(mCellularSignalStrengthDbm);
+ dest.writeInt(mCellularSignalStrengthDb);
+ dest.writeBoolean(mIsSameRegisteredCell);
}
/** Implement the Parcelable interface */
@@ -179,7 +195,9 @@
in.readLong(), in.readLong(), in.readLong(),
in.readLong(), in.readLong(), in.readLong(),
in.readLong(), in.readLong(), in.readInt(),
- in.readInt(), in.readInt(), in.readInt()
+ in.readInt(), in.readInt(), in.readInt(),
+ in.readInt(), in.readInt(), in.readInt(),
+ in.readBoolean()
);
}
@@ -304,4 +322,30 @@
public int getRxLinkSpeedMbps() {
return mRxLinkSpeedMbps;
}
+
+ /** Cellular data network type currently in use on the device for data transmission */
+ @NetworkType public int getCellularDataNetworkType() {
+ return mCellularDataNetworkType;
+ }
+
+ /**
+ * Cellular signal strength in dBm, NR: CsiRsrp, LTE: Rsrp, WCDMA/TDSCDMA: Rscp,
+ * CDMA: Rssi, EVDO: Rssi, GSM: Rssi
+ */
+ public int getCellularSignalStrengthDbm() {
+ return mCellularSignalStrengthDbm;
+ }
+
+ /**
+ * Cellular signal strength in dB, NR: CsiSinr, LTE: Rsrq, WCDMA: EcNo, TDSCDMA: invalid,
+ * CDMA: Ecio, EVDO: SNR, GSM: invalid
+ */
+ public int getCellularSignalStrengthDb() {
+ return mCellularSignalStrengthDb;
+ }
+
+ /** Whether the primary registered cell of current entry is same as that of previous entry */
+ public boolean getIsSameRegisteredCell() {
+ return mIsSameRegisteredCell;
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index b225116..daea601 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -18,6 +18,7 @@
import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.net.NetworkSpecifier;
@@ -302,12 +303,6 @@
/**
* A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
* peer.
- * <p>
- * Note that all Wi-Fi Aware connection specifier objects must call the
- * {@link Builder#setDiscoverySession(DiscoverySession)} to specify the context
- * within which the connection is created, and
- * {@link Builder#setPeerHandle(PeerHandle)} to specify the peer to which the
- * connection is created.
*/
public static final class Builder {
private DiscoverySession mDiscoverySession;
@@ -318,42 +313,27 @@
private int mTransportProtocol = -1; // invalid value
/**
- * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
- * discovery session in whose context the connection is created.
- * <p>
- * Note: this method must be called for any connection request!
+ * Create a builder for {@link WifiAwareNetworkSpecifier} used in requests to set up a
+ * Wi-Fi Aware connection with a peer.
*
- * @param discoverySession A Wi-Fi Aware discovery session.
- * @return the current {@link Builder} builder, enabling chaining of builder
- * methods.
- */
- public @NonNull Builder setDiscoverySession(@NonNull DiscoverySession discoverySession) {
- if (discoverySession == null) {
- throw new IllegalArgumentException("Non-null discoverySession required");
- }
- mDiscoverySession = discoverySession;
- return this;
- }
-
- /**
- * Configure the {@link PeerHandle} of the peer to which the Wi-Fi Aware connection is
- * requested. The peer is discovered through Wi-Fi Aware discovery,
- * <p>
- * Note: this method must be called for any connection request!
- *
- * @param peerHandle The peer's handle obtained through
+ * @param discoverySession A Wi-Fi Aware discovery session in whose context the connection
+ * is created.
+ * @param peerHandle The handle of the peer to which the Wi-Fi Aware connection is
+ * requested. The peer is discovered through Wi-Fi Aware discovery. The
+ * handle can be obtained through
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
* or
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
- * @return the current {@link Builder} builder, enabling chaining of builder
- * methods.
*/
- public @NonNull Builder setPeerHandle(@NonNull PeerHandle peerHandle) {
+ public Builder(@NonNull DiscoverySession discoverySession, @NonNull PeerHandle peerHandle) {
+ if (discoverySession == null) {
+ throw new IllegalArgumentException("Non-null discoverySession required");
+ }
if (peerHandle == null) {
throw new IllegalArgumentException("Non-null peerHandle required");
}
+ mDiscoverySession = discoverySession;
mPeerHandle = peerHandle;
- return this;
}
/**
@@ -407,7 +387,7 @@
* @return the current {@link Builder} builder, enabling chaining of builder
* methods.
*/
- public @NonNull Builder setPort(int port) {
+ public @NonNull Builder setPort(@IntRange(from = 0, to = 65535) int port) {
if (port <= 0 || port > 65535) {
throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
}
@@ -432,7 +412,8 @@
* @return the current {@link Builder} builder, enabling chaining of builder
* methods.
*/
- public @NonNull Builder setTransportProtocol(int transportProtocol) {
+ public @NonNull
+ Builder setTransportProtocol(@IntRange(from = 0, to = 255) int transportProtocol) {
if (transportProtocol < 0 || transportProtocol > 255) {
throw new IllegalArgumentException(
"The transport protocol must be in range [0, 255]");
@@ -460,6 +441,9 @@
if (mDiscoverySession == null) {
throw new IllegalStateException("Null discovery session!?");
}
+ if (mPeerHandle == null) {
+ throw new IllegalStateException("Null peerHandle!?");
+ }
if (mPskPassphrase != null & mPmk != null) {
throw new IllegalStateException(
"Can only specify a Passphrase or a PMK - not both!");
@@ -481,10 +465,6 @@
}
}
- if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
- throw new IllegalStateException("Null peerHandle!?");
- }
-
return new WifiAwareNetworkSpecifier(
WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 6ec64ff..beed666 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -423,4 +423,68 @@
mEnterpriseConfig.setPassword(password);
assertFalse(mEnterpriseConfig.toString().contains(password));
}
+
+ /** Verifies that certificate ownership flag is set correctly */
+ @Test
+ public void testIsAppInstalledDeviceKeyAndCert() {
+ // First make sure that app didn't install anything
+ assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+ assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+
+ // Then app loads keys via the enterprise config API
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ X509Certificate cert0 = FakeKeys.CLIENT_CERT;
+ X509Certificate cert1 = FakeKeys.CA_CERT1;
+ X509Certificate[] clientChain = new X509Certificate[] {cert0, cert1};
+ mEnterpriseConfig.setClientKeyEntryWithCertificateChain(clientKey, clientChain);
+ X509Certificate[] result = mEnterpriseConfig.getClientCertificateChain();
+ assertEquals(result.length, 2);
+ assertTrue(result[0] == cert0 && result[1] == cert1);
+ assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
+
+ // Make sure it is the owner now
+ assertTrue(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+ assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+ }
+
+ /** Verifies that certificate ownership flag is set correctly */
+ @Test
+ public void testIsAppInstalledCaCert() {
+ // First make sure that app didn't install anything
+ assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+ assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+
+ // Then app loads CA cert via the enterprise config API
+ X509Certificate cert = FakeKeys.CA_CERT1;
+ mEnterpriseConfig.setCaCertificate(cert);
+ X509Certificate result = mEnterpriseConfig.getCaCertificate();
+ assertTrue(result == cert);
+
+ // Make sure it is the owner now
+ assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+ assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
+ }
+
+ /** Verifies that certificate ownership flag is set correctly */
+ @Test
+ public void testIsAppInstalledCaCerts() {
+ // First make sure that app didn't install anything
+ assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+ assertFalse(mEnterpriseConfig.isAppInstalledCaCert());
+
+ // Then app loads CA cert via the enterprise config API
+ X509Certificate cert0 = FakeKeys.CA_CERT0;
+ X509Certificate cert1 = FakeKeys.CA_CERT1;
+ X509Certificate[] cert = new X509Certificate[] {cert0, cert1};
+
+ mEnterpriseConfig.setCaCertificates(cert);
+ X509Certificate[] result = mEnterpriseConfig.getCaCertificates();
+ assertEquals(result.length, 2);
+ assertTrue(result[0] == cert0 && result[1] == cert1);
+// assertTrue(mEnterpriseConfig.getClientCertificate() == cert0);
+
+ // Make sure it is the owner now
+ assertFalse(mEnterpriseConfig.isAppInstalledDeviceKeyAndCert());
+ assertTrue(mEnterpriseConfig.isAppInstalledCaCert());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
index 8e37113..cd60f02 100644
--- a/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiUsabilityStatsEntryTest.java
@@ -74,7 +74,8 @@
private static WifiUsabilityStatsEntry createResult() {
return new WifiUsabilityStatsEntry(
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, true
);
}
@@ -111,5 +112,10 @@
assertEquals(expected.getProbeMcsRateSinceLastUpdate(),
actual.getProbeMcsRateSinceLastUpdate());
assertEquals(expected.getRxLinkSpeedMbps(), actual.getRxLinkSpeedMbps());
+ assertEquals(expected.getCellularDataNetworkType(), actual.getCellularDataNetworkType());
+ assertEquals(expected.getCellularSignalStrengthDbm(),
+ actual.getCellularSignalStrengthDbm());
+ assertEquals(expected.getCellularSignalStrengthDb(), actual.getCellularSignalStrengthDb());
+ assertEquals(expected.getIsSameRegisteredCell(), actual.getIsSameRegisteredCell());
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 657a338..905540e 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -958,8 +958,8 @@
WifiAwareNetworkSpecifier ns =
(WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen(
peerHandle);
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession.getValue()).setPeerHandle(peerHandle).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(
+ publishSession.getValue(), peerHandle).build();
// validate format
collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -979,9 +979,8 @@
// (4) request an encrypted (PMK) network specifier from the session
ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk(
peerHandle, pmk);
- nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).setPort(
- port).setTransportProtocol(transportProtocol).build();
+ nsb = new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(), peerHandle).setPmk(
+ pmk).setPort(port).setTransportProtocol(transportProtocol).build();
// validate format
collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1005,9 +1004,9 @@
(WifiAwareNetworkSpecifier) publishSession.getValue()
.createNetworkSpecifierPassphrase(
peerHandle, passphrase);
- nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
- passphrase).setPort(port).setTransportProtocol(transportProtocol).build();
+ nsb = new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(),
+ peerHandle).setPskPassphrase(passphrase).setPort(port).setTransportProtocol(
+ transportProtocol).build();
// validate format
collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1255,16 +1254,15 @@
// (3) create network specifier
if (doPmk) {
if (useBuilder) {
- new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).build();
+ new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(), peerHandle).setPmk(
+ pmk).build();
} else {
publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
}
} else {
if (useBuilder) {
- new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
- passphrase).build();
+ new WifiAwareNetworkSpecifier.Builder(publishSession.getValue(),
+ peerHandle).setPskPassphrase(passphrase).build();
} else {
publishSession.getValue().createNetworkSpecifierPassphrase(peerHandle, passphrase);
}
@@ -1353,8 +1351,8 @@
DiscoverySession publishSession = executeSessionStartup(true);
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession).setPeerHandle(peerHandle).setPmk(pmk).setPort(port).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+ peerHandle).setPmk(pmk).setPort(port).build();
}
/**
@@ -1368,8 +1366,8 @@
DiscoverySession publishSession = executeSessionStartup(true);
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession).setPeerHandle(peerHandle).setPort(port).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+ peerHandle).setPort(port).build();
}
/**
@@ -1383,8 +1381,8 @@
DiscoverySession subscribeSession = executeSessionStartup(false);
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- subscribeSession).setPeerHandle(peerHandle).setPort(port).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(subscribeSession,
+ peerHandle).setPort(port).build();
}
/**
@@ -1403,27 +1401,23 @@
DiscoverySession publishSession = executeSessionStartup(true);
try {
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
- .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
- .setPmk(pmk).setTransportProtocol(tpNegative).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+ peerHandle).setPmk(pmk).setTransportProtocol(tpNegative).build();
assertTrue("No exception on negative transport protocol!", false);
} catch (IllegalArgumentException e) {
// nop - exception is correct!
}
try {
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
- .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
- .setPmk(pmk).setTransportProtocol(tpTooLarge).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+ peerHandle).setPmk(pmk).setTransportProtocol(tpTooLarge).build();
assertTrue("No exception on >255 transport protocol!", false);
} catch (IllegalArgumentException e) {
// nop - exception is correct!
}
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
- .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
- .setPmk(pmk).setTransportProtocol(tpSmallest).build();
- nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
- publishSession).setPeerHandle(peerHandle).setPmk(pmk).setTransportProtocol(
- tpLargest).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+ peerHandle).setPmk(pmk).setTransportProtocol(tpSmallest).build();
+ nsb = new WifiAwareNetworkSpecifier.Builder(publishSession, peerHandle).setPmk(
+ pmk).setTransportProtocol(tpLargest).build();
}
/**
@@ -1437,9 +1431,8 @@
DiscoverySession publishSession = executeSessionStartup(true);
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
- .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
- .setTransportProtocol(transportProtocol).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(publishSession,
+ peerHandle).setTransportProtocol(transportProtocol).build();
}
/**
@@ -1453,9 +1446,8 @@
DiscoverySession subscribeSession = executeSessionStartup(false);
- WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
- .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
- .setTransportProtocol(transportProtocol).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder(subscribeSession,
+ peerHandle).setTransportProtocol(transportProtocol).build();
}
/*