diff options
148 files changed, 3784 insertions, 833 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java index a0e83daf877d..bb94275fc409 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java @@ -144,14 +144,18 @@ public final class ConnectivityController extends RestrictingController implemen public void startTrackingRestrictedJobLocked(JobStatus jobStatus) { // Don't need to start tracking the job. If the job needed network, it would already be // tracked. - updateConstraintsSatisfied(jobStatus); + if (jobStatus.hasConnectivityConstraint()) { + updateConstraintsSatisfied(jobStatus); + } } @Override public void stopTrackingRestrictedJobLocked(JobStatus jobStatus) { // Shouldn't stop tracking the job here. If the job was tracked, it still needs network, // even after being unrestricted. - updateConstraintsSatisfied(jobStatus); + if (jobStatus.hasConnectivityConstraint()) { + updateConstraintsSatisfied(jobStatus); + } } /** diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index ac66d1b7f4ad..d59270c6a51b 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -223,7 +223,7 @@ public final class MediaParser { public static final class SeekPoint { /** A {@link SeekPoint} whose time and byte offset are both set to 0. */ - public static final @NonNull SeekPoint START = new SeekPoint(0, 0); + @NonNull public static final SeekPoint START = new SeekPoint(0, 0); /** The time of the seek point, in microseconds. */ public final long timeUs; @@ -241,7 +241,8 @@ public final class MediaParser { } @Override - public @NonNull String toString() { + @NonNull + public String toString() { return "[timeUs=" + timeUs + ", position=" + position + "]"; } @@ -414,7 +415,8 @@ public final class MediaParser { * @return A new instance. * @throws IllegalArgumentException If an invalid name is provided. */ - public static @NonNull MediaParser createByName( + @NonNull + public static MediaParser createByName( @NonNull String name, @NonNull OutputConsumer outputConsumer) { String[] nameAsArray = new String[] {name}; assertValidNames(nameAsArray); @@ -431,7 +433,8 @@ public final class MediaParser { * default array of names is used. * @return A new instance. */ - public static @NonNull MediaParser create( + @NonNull + public static MediaParser create( @NonNull OutputConsumer outputConsumer, @NonNull String... extractorNames) { assertValidNames(extractorNames); if (extractorNames.length == 0) { @@ -448,7 +451,8 @@ public final class MediaParser { * * <p>TODO: List which properties are taken into account. E.g. MimeType. */ - public static @NonNull List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) { + @NonNull + public static List<String> getExtractorNames(@NonNull MediaFormat mediaFormat) { throw new UnsupportedOperationException(); } @@ -479,7 +483,8 @@ public final class MediaParser { * @return The name of the backing extractor implementation, or null if the backing extractor * implementation has not yet been selected. */ - public @Nullable String getExtractorName() { + @Nullable + public String getExtractorName() { return mExtractorName; } diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp index dd174734df6d..245a96b99148 100644 --- a/apex/sdkextensions/framework/Android.bp +++ b/apex/sdkextensions/framework/Android.bp @@ -32,6 +32,7 @@ java_library { libs: [ "framework-annotations-lib" ], permitted_packages: [ "android.os.ext" ], installable: true, + plugins: ["java_api_finder"], visibility: [ "//frameworks/base/apex/sdkextensions", "//frameworks/base/apex/sdkextensions/testing", diff --git a/api/current.txt b/api/current.txt index c09dad40e532..e614f17cce92 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10173,6 +10173,7 @@ package android.content { field public static final String STORAGE_STATS_SERVICE = "storagestats"; field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth"; field public static final String TELECOM_SERVICE = "telecom"; + field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TELEPHONY_SERVICE = "phone"; field public static final String TELEPHONY_SUBSCRIPTION_SERVICE = "telephony_subscription_service"; field public static final String TEXT_CLASSIFICATION_SERVICE = "textclassification"; @@ -12016,6 +12017,7 @@ package android.content.pm { field public static final String FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING = "android.hardware.camera.capability.manual_post_processing"; field public static final String FEATURE_CAMERA_CAPABILITY_MANUAL_SENSOR = "android.hardware.camera.capability.manual_sensor"; field public static final String FEATURE_CAMERA_CAPABILITY_RAW = "android.hardware.camera.capability.raw"; + field public static final String FEATURE_CAMERA_CONCURRENT = "android.hardware.camera.concurrent"; field public static final String FEATURE_CAMERA_EXTERNAL = "android.hardware.camera.external"; field public static final String FEATURE_CAMERA_FLASH = "android.hardware.camera.flash"; field public static final String FEATURE_CAMERA_FRONT = "android.hardware.camera.front"; @@ -12073,6 +12075,7 @@ package android.content.pm { field public static final String FEATURE_SENSOR_GYROSCOPE = "android.hardware.sensor.gyroscope"; field public static final String FEATURE_SENSOR_HEART_RATE = "android.hardware.sensor.heartrate"; field public static final String FEATURE_SENSOR_HEART_RATE_ECG = "android.hardware.sensor.heartrate.ecg"; + field public static final String FEATURE_SENSOR_HINGE_ANGLE = "android.hardware.sensor.hinge_angle"; field public static final String FEATURE_SENSOR_LIGHT = "android.hardware.sensor.light"; field public static final String FEATURE_SENSOR_PROXIMITY = "android.hardware.sensor.proximity"; field public static final String FEATURE_SENSOR_RELATIVE_HUMIDITY = "android.hardware.sensor.relative_humidity"; @@ -17172,6 +17175,7 @@ package android.hardware.camera2 { field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE; + field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_STREAM_COMBINATIONS; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP; field @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES; @@ -17261,6 +17265,8 @@ package android.hardware.camera2 { public final class CameraManager { method @NonNull public android.hardware.camera2.CameraCharacteristics getCameraCharacteristics(@NonNull String) throws android.hardware.camera2.CameraAccessException; method @NonNull public String[] getCameraIdList() throws android.hardware.camera2.CameraAccessException; + method @NonNull public java.util.Set<java.util.Set<java.lang.String>> getConcurrentStreamingCameraIds() throws android.hardware.camera2.CameraAccessException; + method @RequiresPermission(android.Manifest.permission.CAMERA) public boolean isConcurrentSessionConfigurationSupported(@NonNull java.util.Map<java.lang.String,android.hardware.camera2.params.SessionConfiguration>) throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull android.hardware.camera2.CameraDevice.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(android.Manifest.permission.CAMERA) public void openCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; method public void registerAvailabilityCallback(@NonNull android.hardware.camera2.CameraManager.AvailabilityCallback, @Nullable android.os.Handler); @@ -45211,6 +45217,7 @@ package android.telecom { method public void registerCallback(android.telecom.Call.Callback); method public void registerCallback(android.telecom.Call.Callback, android.os.Handler); method public void reject(boolean, String); + method public void reject(int); method public void removeExtras(java.util.List<java.lang.String>); method public void removeExtras(java.lang.String...); method public void respondToRttRequest(int, boolean); @@ -45226,6 +45233,8 @@ package android.telecom { 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 REJECT_REASON_DECLINED = 1; // 0x1 + field public static final int REJECT_REASON_UNWANTED = 2; // 0x2 field public static final int STATE_ACTIVE = 4; // 0x4 field public static final int STATE_AUDIO_PROCESSING = 12; // 0xc field public static final int STATE_CONNECTING = 9; // 0x9 @@ -45493,6 +45502,7 @@ package android.telecom { method public void onPostDialContinue(boolean); method public void onPullExternalCall(); method public void onReject(); + method public void onReject(int); method public void onReject(String); method public void onSeparate(); method public void onShowIncomingCallUi(); @@ -48252,13 +48262,20 @@ package android.telephony.ims { public final class ImsException extends java.lang.Exception { method public int getCode(); + field public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; // 0x3 field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 } + public class ImsManager { + method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); + field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; + field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; + } + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting(); diff --git a/api/system-current.txt b/api/system-current.txt index 6a88822ac8da..cc4b1221c756 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1780,6 +1780,7 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; + field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String EUICC_CARD_SERVICE = "euicc_card"; field public static final String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final String NETD_SERVICE = "netd"; @@ -1795,7 +1796,6 @@ package android.content { field public static final String STATUS_BAR_SERVICE = "statusbar"; field public static final String SYSTEM_CONFIG_SERVICE = "system_config"; field public static final String SYSTEM_UPDATE_SERVICE = "system_update"; - field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TELEPHONY_REGISTRY_SERVICE = "telephony_registry"; field public static final String TETHERING_SERVICE = "tethering"; field public static final String VR_SERVICE = "vrmanager"; @@ -2519,7 +2519,7 @@ package android.hardware.display { method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String); method public android.util.Pair<float[],float[]> getCurve(); method public float getShortTermModelLowerLuxMultiplier(); - method public long getShortTermModelTimeout(); + method public long getShortTermModelTimeoutMillis(); method public float getShortTermModelUpperLuxMultiplier(); method public boolean shouldCollectColorSamples(); method public void writeToParcel(android.os.Parcel, int); @@ -2536,7 +2536,7 @@ package android.hardware.display { method public int getMaxCorrectionsByPackageName(); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float); - method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long); + method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean); } @@ -6078,6 +6078,19 @@ package android.net { method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network); } + public class EthernetManager { + method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback); + } + + public static interface EthernetManager.TetheredInterfaceCallback { + method public void onAvailable(@NonNull String); + method public void onUnavailable(); + } + + public static class EthernetManager.TetheredInterfaceRequest { + method public void release(); + } + public class InvalidPacketException extends java.lang.Exception { ctor public InvalidPacketException(int); field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb @@ -6507,6 +6520,7 @@ package android.net { field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 field public static final int TETHERING_INVALID = -1; // 0xffffffff field public static final int TETHERING_NCM = 4; // 0x4 field public static final int TETHERING_USB = 1; // 0x1 @@ -7557,12 +7571,12 @@ package android.net.wifi { } public class WifiInfo implements android.os.Parcelable { - method @Nullable public String getAppPackageName(); - method public double getRxSuccessRate(); + method public double getLostTxPacketsPerSecond(); + method @Nullable public String getRequestingPackageName(); + method public double getRetriedTxPacketsPerSecond(); method public int getScore(); - method public double getTxBadRate(); - method public double getTxRetriesRate(); - method public double getTxSuccessRate(); + method public double getSuccessfulRxPacketsPerSecond(); + method public double getSuccessfulTxPacketsPerSecond(); method public boolean isEphemeral(); method public boolean isOsuAp(); method public boolean isPasspointAp(); @@ -7590,7 +7604,6 @@ package android.net.wifi { method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String); - method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void enableVerboseLogging(int); method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset(); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>); @@ -7602,7 +7615,6 @@ package android.net.wifi { method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration(); - method public int getVerboseLoggingLevel(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener); method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState(); @@ -7612,6 +7624,7 @@ package android.net.wifi { method @Deprecated public boolean isDeviceToDeviceRttSupported(); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean isDualModeSupported(); method public boolean isPortableHotspotSupported(); + method public boolean isVerboseLoggingEnabled(); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled(); method public boolean isWifiScannerSupported(); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerNetworkRequestMatchCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.NetworkRequestMatchCallback); @@ -7628,6 +7641,7 @@ package android.net.wifi { method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMacRandomizationSettingPasspointEnabled(@NonNull String, boolean); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setMeteredOverridePasspoint(@NonNull String, int); method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public boolean setSoftApConfiguration(@NonNull android.net.wifi.SoftApConfiguration); + method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setVerboseLoggingEnabled(boolean); method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration); method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public boolean setWifiConnectedNetworkScorer(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.WifiConnectedNetworkScorer); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback); @@ -8592,9 +8606,6 @@ package android.os { field public static final int STATUS_SUCCESS = 0; // 0x0 } - @IntDef(prefix={"STATUS_"}, value={android.os.HwParcel.STATUS_SUCCESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface HwParcel.Status { - } - public interface IHwBinder { method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long); method public android.os.IHwInterface queryLocalInterface(String); @@ -9031,23 +9042,15 @@ package android.os.connectivity { } public final class WifiActivityEnergyInfo implements android.os.Parcelable { - ctor public WifiActivityEnergyInfo(long, int, long, long, long, long); + ctor public WifiActivityEnergyInfo(long, int, @IntRange(from=0) long, @IntRange(from=0) long, @IntRange(from=0) long, @IntRange(from=0) long); method public int describeContents(); - method public long getControllerEnergyUsedMicroJoules(); - method public long getControllerIdleDurationMillis(); - method public long getControllerRxDurationMillis(); - method public long getControllerScanDurationMillis(); - method public long getControllerTxDurationMillis(); + method @IntRange(from=0) public long getControllerEnergyUsedMicroJoules(); + method @IntRange(from=0) public long getControllerIdleDurationMillis(); + method @IntRange(from=0) public long getControllerRxDurationMillis(); + method @IntRange(from=0) public long getControllerScanDurationMillis(); + method @IntRange(from=0) public long getControllerTxDurationMillis(); method public int getStackState(); method public long getTimeSinceBootMillis(); - method public boolean isValid(); - method public void setControllerEnergyUsedMicroJoules(long); - method public void setControllerIdleDurationMillis(long); - method public void setControllerRxDurationMillis(long); - method public void setControllerScanDurationMillis(long); - method public void setControllerTxDurationMillis(long); - method public void setStackState(int); - method public void setTimeSinceBootMillis(long); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.os.connectivity.WifiActivityEnergyInfo> CREATOR; field public static final int STACK_STATE_INVALID = 0; // 0x0 @@ -13007,15 +13010,12 @@ package android.telephony.ims { } public class ImsManager { - method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; - field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); @@ -13383,8 +13383,8 @@ package android.telephony.ims { method public int describeContents(); method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags(); method @NonNull public android.net.Uri getContactUri(); - method @Nullable public android.net.Uri getServiceUri(int); - method public boolean isCapable(int); + method @Nullable public android.net.Uri getServiceUri(long); + method public boolean isCapable(long); method public boolean isCapable(@NonNull String); method public void writeToParcel(@NonNull android.os.Parcel, int); field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000 @@ -13406,6 +13406,7 @@ package android.telephony.ims { field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100 field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000 field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000 + field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000 field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000 field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000 field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000 @@ -13414,6 +13415,7 @@ package android.telephony.ims { field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000 field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000 field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800 + field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000 field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200 field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR; @@ -13421,14 +13423,16 @@ package android.telephony.ims { public static class RcsContactUceCapability.Builder { ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri); - method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int, @NonNull android.net.Uri); - method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(int); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long); method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String); method @NonNull public android.telephony.ims.RcsContactUceCapability build(); } public class RcsUceAdapter { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd field public static final int ERROR_FORBIDDEN = 6; // 0x6 @@ -13450,6 +13454,12 @@ package android.telephony.ims { field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3 } + public static class RcsUceAdapter.CapabilitiesCallback { + ctor public RcsUceAdapter.CapabilitiesCallback(); + method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>); + method public void onError(int); + } + } package android.telephony.ims.feature { @@ -13539,6 +13549,8 @@ package android.telephony.ims.feature { public class RcsFeature extends android.telephony.ims.feature.ImsFeature { ctor public RcsFeature(); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl(); + method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl(); method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities); method public void onFeatureReady(); method public void onFeatureRemoved(); @@ -13731,6 +13743,71 @@ package android.telephony.ims.stub { field public static final int INVALID_RESULT = -1; // 0xffffffff } + public class RcsCapabilityExchange { + ctor public RcsCapabilityExchange(); + method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException; + field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4 + field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2 + field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6 + field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3 + field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7 + field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9 + field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8 + field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb + field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa + field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0 + field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1 + } + + public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsPresenceExchangeImplBase(); + method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException; + method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException; + method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException; + method public final void onUnpublish() throws android.telephony.ims.ImsException; + method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int); + method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7 + field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9 + field public static final int RESPONSE_FORBIDDEN = 3; // 0x3 + field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2 + field public static final int RESPONSE_NOT_FOUND = 4; // 0x4 + field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1 + field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7 + field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8 + field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + } + + public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsSipOptionsImplBase(); + method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int); + method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int); + method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5 + field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4 + field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_NOT_FOUND = 3; // 0x3 + field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1 + } + } package android.telephony.mbms { diff --git a/api/test-current.txt b/api/test-current.txt index e7a0cf6c2f4d..b35bca8ea2ea 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -771,12 +771,12 @@ package android.content { field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; + field public static final String ETHERNET_SERVICE = "ethernet"; field public static final String NETWORK_STACK_SERVICE = "network_stack"; field public static final String PERMISSION_SERVICE = "permission"; field public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String STATUS_BAR_SERVICE = "statusbar"; - field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; field public static final String TEST_NETWORK_SERVICE = "test_network"; } @@ -1091,7 +1091,7 @@ package android.hardware.display { method @Nullable public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(@NonNull String); method public android.util.Pair<float[],float[]> getCurve(); method public float getShortTermModelLowerLuxMultiplier(); - method public long getShortTermModelTimeout(); + method public long getShortTermModelTimeoutMillis(); method public float getShortTermModelUpperLuxMultiplier(); method public boolean shouldCollectColorSamples(); method public void writeToParcel(android.os.Parcel, int); @@ -1108,7 +1108,7 @@ package android.hardware.display { method public int getMaxCorrectionsByPackageName(); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setDescription(@Nullable String); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelLowerLuxMultiplier(@FloatRange(from=0.0f) float); - method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeout(long); + method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelTimeoutMillis(long); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShortTermModelUpperLuxMultiplier(@FloatRange(from=0.0f) float); method @NonNull public android.hardware.display.BrightnessConfiguration.Builder setShouldCollectColorSamples(boolean); } @@ -1612,6 +1612,19 @@ package android.net { field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT"; } + public class EthernetManager { + method @NonNull public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull android.net.EthernetManager.TetheredInterfaceCallback); + } + + public static interface EthernetManager.TetheredInterfaceCallback { + method public void onAvailable(@NonNull String); + method public void onUnavailable(); + } + + public static class EthernetManager.TetheredInterfaceRequest { + method public void release(); + } + public final class IpPrefix implements android.os.Parcelable { ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int); ctor public IpPrefix(@NonNull String); @@ -1760,6 +1773,7 @@ package android.net { field public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; field public static final String EXTRA_ERRORED_TETHER = "erroredArray"; field public static final int TETHERING_BLUETOOTH = 2; // 0x2 + field public static final int TETHERING_ETHERNET = 5; // 0x5 field public static final int TETHERING_INVALID = -1; // 0xffffffff field public static final int TETHERING_NCM = 4; // 0x4 field public static final int TETHERING_USB = 1; // 0x1 @@ -2204,9 +2218,6 @@ package android.os { field public static final int STATUS_SUCCESS = 0; // 0x0 } - @IntDef(prefix={"STATUS_"}, value={android.os.HwParcel.STATUS_SUCCESS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface HwParcel.Status { - } - public interface IHwBinder { method public boolean linkToDeath(android.os.IHwBinder.DeathRecipient, long); method public android.os.IHwInterface queryLocalInterface(String); @@ -3793,15 +3804,12 @@ package android.telephony.ims { } public class ImsManager { - method @NonNull public android.telephony.ims.ImsMmTelManager getImsMmTelManager(int); method @NonNull public android.telephony.ims.ImsRcsManager getImsRcsManager(int); field public static final String ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION = "com.android.internal.intent.action.ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION"; - field public static final String ACTION_WFC_IMS_REGISTRATION_ERROR = "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_MESSAGE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_MESSAGE"; - field public static final String EXTRA_WFC_REGISTRATION_FAILURE_TITLE = "android.telephony.ims.extra.WFC_REGISTRATION_FAILURE_TITLE"; } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { + method @Deprecated @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting(); @@ -4161,8 +4169,60 @@ package android.telephony.ims { method public void onProvisioningStringChanged(int, @NonNull String); } + public final class RcsContactUceCapability implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getCapableExtensionTags(); + method @NonNull public android.net.Uri getContactUri(); + method @Nullable public android.net.Uri getServiceUri(long); + method public boolean isCapable(long); + method public boolean isCapable(@NonNull String); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000 + field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000 + field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000 + field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2 + field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4 + field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1 + field public static final int CAPABILITY_DISCOVERY_VIA_PRESENCE = 4096; // 0x1000 + field public static final int CAPABILITY_FILE_TRANSFER = 8; // 0x8 + field public static final int CAPABILITY_FILE_TRANSFER_HTTP = 64; // 0x40 + field public static final int CAPABILITY_FILE_TRANSFER_SMS = 128; // 0x80 + field public static final int CAPABILITY_FILE_TRANSFER_STORE_FORWARD = 32; // 0x20 + field public static final int CAPABILITY_FILE_TRANSFER_THUMBNAIL = 16; // 0x10 + field public static final int CAPABILITY_GEOLOCATION_PULL = 131072; // 0x20000 + field public static final int CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER = 262144; // 0x40000 + field public static final int CAPABILITY_GEOLOCATION_PUSH = 32768; // 0x8000 + field public static final int CAPABILITY_GEOLOCATION_PUSH_SMS = 65536; // 0x10000 + field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100 + field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000 + field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000 + field public static final int CAPABILITY_MMTEL_CALL_COMPOSER = 1073741824; // 0x40000000 + field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000 + field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000 + field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000 + field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000 + field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000 + field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000 + field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000 + field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800 + field public static final int CAPABILITY_STANDALONE_CHAT_BOT = 536870912; // 0x20000000 + field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400 + field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200 + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsContactUceCapability> CREATOR; + } + + public static class RcsContactUceCapability.Builder { + ctor public RcsContactUceCapability.Builder(@NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long, @NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(long); + method @NonNull public android.telephony.ims.RcsContactUceCapability.Builder add(@NonNull String); + method @NonNull public android.telephony.ims.RcsContactUceCapability build(); + } + public class RcsUceAdapter { + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getUcePublishState() throws android.telephony.ims.ImsException; method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException; + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void requestCapabilities(@NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.net.Uri>, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; field public static final int ERROR_ALREADY_IN_QUEUE = 13; // 0xd field public static final int ERROR_FORBIDDEN = 6; // 0x6 @@ -4184,6 +4244,12 @@ package android.telephony.ims { field public static final int PUBLISH_STATE_VOLTE_PROVISION_ERROR = 3; // 0x3 } + public static class RcsUceAdapter.CapabilitiesCallback { + ctor public RcsUceAdapter.CapabilitiesCallback(); + method public void onCapabilitiesReceived(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>); + method public void onError(int); + } + } package android.telephony.ims.feature { @@ -4273,6 +4339,8 @@ package android.telephony.ims.feature { public class RcsFeature extends android.telephony.ims.feature.ImsFeature { ctor public RcsFeature(); method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method @NonNull public android.telephony.ims.stub.RcsSipOptionsImplBase getOptionsExchangeImpl(); + method @NonNull public android.telephony.ims.stub.RcsPresenceExchangeImplBase getPresenceExchangeImpl(); method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities); method public void onFeatureReady(); method public void onFeatureRemoved(); @@ -4465,6 +4533,71 @@ package android.telephony.ims.stub { field public static final int INVALID_RESULT = -1; // 0xffffffff } + public class RcsCapabilityExchange { + ctor public RcsCapabilityExchange(); + method public final void onCommandUpdate(int, int) throws android.telephony.ims.ImsException; + field public static final int COMMAND_CODE_FETCH_ERROR = 4; // 0x4 + field public static final int COMMAND_CODE_GENERIC_FAILURE = 2; // 0x2 + field public static final int COMMAND_CODE_INSUFFICIENT_MEMORY = 6; // 0x6 + field public static final int COMMAND_CODE_INVALID_PARAM = 3; // 0x3 + field public static final int COMMAND_CODE_LOST_NETWORK_CONNECTION = 7; // 0x7 + field public static final int COMMAND_CODE_NOT_FOUND = 9; // 0x9 + field public static final int COMMAND_CODE_NOT_SUPPORTED = 8; // 0x8 + field public static final int COMMAND_CODE_NO_CHANGE_IN_CAP = 11; // 0xb + field public static final int COMMAND_CODE_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int COMMAND_CODE_SERVICE_UNAVAILABLE = 10; // 0xa + field public static final int COMMAND_CODE_SERVICE_UNKNOWN = 0; // 0x0 + field public static final int COMMAND_CODE_SUCCESS = 1; // 0x1 + } + + public class RcsPresenceExchangeImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsPresenceExchangeImplBase(); + method public final void onCapabilityRequestResponse(@NonNull java.util.List<android.telephony.ims.RcsContactUceCapability>, int) throws android.telephony.ims.ImsException; + method public final void onNetworkResponse(int, @NonNull String, int) throws android.telephony.ims.ImsException; + method public final void onNotifyUpdateCapabilites(int) throws android.telephony.ims.ImsException; + method public final void onUnpublish() throws android.telephony.ims.ImsException; + method public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, int); + method public void updateCapabilities(@NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; // 0x0 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; // 0x6 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; // 0x5 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; // 0x3 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; // 0x4 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; // 0x8 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; // 0x1 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; // 0x2 + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; // 0xa + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; // 0xb + field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; // 0x7 + field public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; // 0x9 + field public static final int RESPONSE_FORBIDDEN = 3; // 0x3 + field public static final int RESPONSE_NOT_AUTHORIZED_FOR_PRESENCE = 2; // 0x2 + field public static final int RESPONSE_NOT_FOUND = 4; // 0x4 + field public static final int RESPONSE_NOT_REGISTERED = 1; // 0x1 + field public static final int RESPONSE_SIP_INTERVAL_TOO_SHORT = 7; // 0x7 + field public static final int RESPONSE_SIP_REQUEST_TIMEOUT = 5; // 0x5 + field public static final int RESPONSE_SIP_SERVICE_UNAVAILABLE = 8; // 0x8 + field public static final int RESPONSE_SUBSCRIBE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_SUBSCRIBE_TOO_LARGE = 6; // 0x6 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + } + + public class RcsSipOptionsImplBase extends android.telephony.ims.stub.RcsCapabilityExchange { + ctor public RcsSipOptionsImplBase(); + method public final void onCapabilityRequestResponse(int, @NonNull String, @Nullable android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public final void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int) throws android.telephony.ims.ImsException; + method public void respondToCapabilityRequest(@NonNull String, @NonNull android.telephony.ims.RcsContactUceCapability, int); + method public void respondToCapabilityRequestWithError(@NonNull android.net.Uri, int, @NonNull String, int); + method public void sendCapabilityRequest(@NonNull android.net.Uri, @NonNull android.telephony.ims.RcsContactUceCapability, int); + field public static final int RESPONSE_BAD_REQUEST = 5; // 0x5 + field public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; // 0x4 + field public static final int RESPONSE_GENERIC_FAILURE = -1; // 0xffffffff + field public static final int RESPONSE_NOT_FOUND = 3; // 0x3 + field public static final int RESPONSE_REQUEST_TIMEOUT = 2; // 0x2 + field public static final int RESPONSE_SUCCESS = 0; // 0x0 + field public static final int RESPONSE_TEMPORARILY_UNAVAILABLE = 1; // 0x1 + } + } package android.telephony.mbms { diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt index a9c18363d8b0..f53548b68a45 100644 --- a/api/test-lint-baseline.txt +++ b/api/test-lint-baseline.txt @@ -2451,8 +2451,6 @@ ProtectedMember: android.view.ViewGroup#resetResolvedDrawables(): -PublicTypedef: android.os.HwParcel.Status: - PublicTypedef: android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability: PublicTypedef: android.telephony.ims.feature.MmTelFeature.ProcessCallResult: diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index d9d5be6e46ec..7011724ef7d4 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -137,7 +137,7 @@ message Atom { DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true]; OverlayStateChanged overlay_state_changed = 59; ForegroundServiceStateChanged foreground_service_state_changed = 60; - CallStateChanged call_state_changed = 61; + CallStateChanged call_state_changed = 61 [(module) = "telecom"]; KeyguardStateChanged keyguard_state_changed = 62 [(module) = "sysui"]; KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63 [(module) = "sysui"]; KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64 [(module) = "sysui"]; @@ -288,8 +288,8 @@ message Atom { MediametricsNuPlayerReported mediametrics_nuplayer_reported = 199; MediametricsRecorderReported mediametrics_recorder_reported = 200; MediametricsDrmManagerReported mediametrics_drmmanager_reported = 201; - CarPowerStateChanged car_power_state_changed = 203; - GarageModeInfo garage_mode_info = 204; + CarPowerStateChanged car_power_state_changed = 203 [(module) = "car"]; + GarageModeInfo garage_mode_info = 204 [(module) = "car"]; TestAtomReported test_atom_reported = 205 [(module) = "cts"]; ContentCaptureCallerMismatchReported content_capture_caller_mismatch_reported = 206; ContentCaptureServiceEvents content_capture_service_events = 207; @@ -324,7 +324,8 @@ message Atom { AppCompatibilityChangeReported app_compatibility_change_reported = 228 [(allow_from_any_uid) = true]; PerfettoUploaded perfetto_uploaded = 229 [(module) = "perfetto"]; - VmsClientConnectionStateChanged vms_client_connection_state_changed = 230; + VmsClientConnectionStateChanged vms_client_connection_state_changed = + 230 [(module) = "car"]; MediaProviderScanEvent media_provider_scan_event = 233 [(module) = "mediaprovider"]; MediaProviderDeletionEvent media_provider_deletion_event = 234 [(module) = "mediaprovider"]; MediaProviderPermissionEvent media_provider_permission_event = @@ -343,6 +344,10 @@ message Atom { NotificationChannelModified notification_panel_modified = 246; IntegrityCheckResultReported integrity_check_result_reported = 247; IntegrityRulesPushed integrity_rules_pushed = 248; + CellBroadcastMessageReported cb_message_reported = + 249 [(module) = "cellbroadcast"]; + CellBroadcastMessageError cb_message_error = + 250 [(module) = "cellbroadcast"]; } // Pulled events will start at field 10000. @@ -412,7 +417,7 @@ message Atom { SurfaceflingerStatsGlobalInfo surfaceflinger_stats_global_info = 10062; SurfaceflingerStatsLayerInfo surfaceflinger_stats_layer_info = 10063; ProcessMemorySnapshot process_memory_snapshot = 10064; - VmsClientStats vms_client_stats = 10065; + VmsClientStats vms_client_stats = 10065 [(module) = "car"]; NotificationRemoteViews notification_remote_views = 10066; DangerousPermissionStateSampled dangerous_permission_state_sampled = 10067; GraphicsStats graphics_stats = 10068; @@ -8112,3 +8117,55 @@ message IntegrityRulesPushed { // identify the rules. optional string rule_version = 3; } + +/** + * Logs when a cell broadcast message is received on the device. + * + * Logged from CellBroadcastService module: + * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/ + */ +message CellBroadcastMessageReported { + // The type of Cell Broadcast message + enum CbType { + UNKNOWN_TYPE = 0; + GSM = 1; + CDMA = 2; + CDMA_SPC = 3; + } + + // GSM, CDMA, CDMA-SCP + optional CbType type = 1; +} + +/** + * Logs when an error occurs while handling a cell broadcast message; + * + * Logged from CellBroadcastService module: + * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/ + */ +message CellBroadcastMessageError { + // The type of error raised when trying to handle a cell broadcast message + enum ErrorType { + UNKNOWN_TYPE = 0; + CDMA_DECODING_ERROR = 1; + CDMA_SCP_EMPTY = 2; + CDMA_SCP_HANDLING_ERROR = 3; + GSM_INVALID_HEADER_LENGTH = 4; + GSM_UNSUPPORTED_HEADER_MESSAGE_TYPE = 5; + GSM_UNSUPPORTED_HEADER_DATA_CODING_SCHEME = 6; + GSM_INVALID_PDU = 7; + GSM_INVALID_GEO_FENCING_DATA = 8; + GSM_UMTS_INVALID_WAC = 9; + FAILED_TO_INSERT_TO_DB = 10; + UNEXPECTED_GEOMETRY_FROM_FWK = 11; + UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12; + UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13; + UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14; + } + + // What kind of error occurred + optional ErrorType type = 1; + + // Exception message (or log message) associated with the error (max 1000 chars) + optional string exception_message = 2; +} diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 5a4d62010f11..c09aa1ff05a8 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -632,22 +632,22 @@ public class ApplicationPackageManager extends PackageManager { private static final int SYS_FEATURE_CACHE_SIZE = 256; private static final String CACHE_KEY_SYS_FEATURE_PROPERTY = "cache_key.has_system_feature"; - private class HasSystemFeatureQuery { + private class SystemFeatureQuery { public final String name; public final int version; - public HasSystemFeatureQuery(String n, int v) { + public SystemFeatureQuery(String n, int v) { name = n; version = v; } @Override public String toString() { - return String.format("HasSystemFeatureQuery(name=\"%s\", version=%d)", + return String.format("SystemFeatureQuery(name=\"%s\", version=%d)", name, version); } @Override public boolean equals(Object o) { - if (o instanceof HasSystemFeatureQuery) { - HasSystemFeatureQuery r = (HasSystemFeatureQuery) o; + if (o instanceof SystemFeatureQuery) { + SystemFeatureQuery r = (SystemFeatureQuery) o; return Objects.equals(name, r.name) && version == r.version; } else { return false; @@ -655,32 +655,32 @@ public class ApplicationPackageManager extends PackageManager { } @Override public int hashCode() { - return Objects.hashCode(name) * 13 + version; + return Objects.hashCode(name) + version; } } - private final PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean> mHasSystemFeatureCache = - new PropertyInvalidatedCache<>( + private final PropertyInvalidatedCache<SystemFeatureQuery, Boolean> mSysFeatureCache = + new PropertyInvalidatedCache<SystemFeatureQuery, Boolean>( SYS_FEATURE_CACHE_SIZE, CACHE_KEY_SYS_FEATURE_PROPERTY) { @Override - protected Boolean recompute(HasSystemFeatureQuery query) { + protected Boolean recompute(SystemFeatureQuery query) { return hasSystemFeatureUncached(query.name, query.version); } }; @Override public boolean hasSystemFeature(String name, int version) { - return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version)); + return mSysFeatureCache.query(new SystemFeatureQuery(name, version)).booleanValue(); } /** @hide */ - public void disableHasSystemFeatureCache() { - mHasSystemFeatureCache.disableLocal(); + public void disableSysFeatureCache() { + mSysFeatureCache.disableLocal(); } /** @hide */ - public static void invalidateHasSystemFeatureCache() { + public static void invalidateSysFeatureCache() { PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SYS_FEATURE_PROPERTY); } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index d665f336ec1d..4b1ba0278682 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -18,6 +18,7 @@ package android.app; import android.app.ITransientNotification; +import android.app.ITransientNotificationCallback; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationChannelGroup; @@ -45,8 +46,7 @@ interface INotificationManager void cancelAllNotifications(String pkg, int userId); void clearData(String pkg, int uid, boolean fromApp); - // TODO: Replace parameter (ITransientNotification callback) with (CharSequence text) - void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId); + void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, int displayId, @nullable ITransientNotificationCallback callback); void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId); void cancelToast(String pkg, IBinder token); void finishToken(String pkg, IBinder token); diff --git a/core/java/android/app/ITransientNotificationCallback.aidl b/core/java/android/app/ITransientNotificationCallback.aidl new file mode 100644 index 000000000000..abe254f2d16a --- /dev/null +++ b/core/java/android/app/ITransientNotificationCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2020, 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.app; + +/** + * Callback object to be called when the associated toast is shown or hidden. + * + * @hide + */ +oneway interface ITransientNotificationCallback { + void onToastShown(); + void onToastHidden(); +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 58a0ea56a65f..a0d5c108869e 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4139,16 +4139,16 @@ public abstract class Context { public static final String LOWPAN_SERVICE = "lowpan"; /** - * Use with {@link #getSystemService(String)} to retrieve a {@link - * android.net.EthernetManager} for handling management of - * Ethernet access. + * Use with {@link #getSystemService(String)} to retrieve a {@link android.net.EthernetManager} + * for handling management of Ethernet access. * * @see #getSystemService(String) * @see android.net.EthernetManager * * @hide */ - @UnsupportedAppUsage + @SystemApi + @TestApi public static final String ETHERNET_SERVICE = "ethernet"; /** @@ -5032,10 +5032,7 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve an * {@link android.telephony.ims.ImsManager}. - * @hide */ - @SystemApi - @TestApi public static final String TELEPHONY_IMS_SERVICE = "telephony_ims"; /** diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 66a2b7a3ac66..b64c001ea6e2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1960,6 +1960,15 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device's main front and back cameras can stream + * concurrently as described in {@link + * android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds()} + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_CAMERA_CONCURRENT = "android.hardware.camera.concurrent"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device is capable of communicating with * consumer IR devices. */ @@ -2326,6 +2335,13 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature}: The device includes a hinge angle sensor. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_SENSOR_HINGE_ANGLE = "android.hardware.sensor.hinge_angle"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports high fidelity sensor processing * capabilities. */ diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index dfc4f0f6586c..b3a1ee2f9b69 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2875,7 +2875,28 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri @NonNull public static final Key<int[]> SCALER_AVAILABLE_ROTATE_AND_CROP_MODES = new Key<int[]>("android.scaler.availableRotateAndCropModes", int[].class); - + /** + * <p>An array of mandatory concurrent stream combinations. + * This is an app-readable conversion of the concurrent mandatory stream combination + * {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p> + * <p>The array of + * {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is + * generated according to the documented + * {@link android.hardware.camera2.CameraDevice#createCaptureSession guideline} for each device + * which has its Id present in the set returned by + * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds}. + * Clients can use the array as a quick reference to find an appropriate camera stream + * combination. + * The mandatory stream combination array will be {@code null} in case the device is not a part + * of at least one set of combinations returned by + * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds}.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + */ + @PublicKey + @NonNull + @SyntheticKey + public static final Key<android.hardware.camera2.params.MandatoryStreamCombination[]> SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS = + new Key<android.hardware.camera2.params.MandatoryStreamCombination[]>("android.scaler.mandatoryConcurrentStreamCombinations", android.hardware.camera2.params.MandatoryStreamCombination[].class); /** * <p>The area of the image sensor which corresponds to active pixels after any geometric * distortion correction has been applied.</p> diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index cc066812ba1f..24d931154533 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -680,6 +680,25 @@ public abstract class CameraDevice implements AutoCloseable { * </table><br> * </p> * + *<p>Devices capable of streaming concurrently with other devices as described by + * {@link android.hardware.camera2.CameraManager#getConcurrentStreamingCameraIds} have the + * following guaranteed streams (when streaming concurrently with other devices)</p> + * + * <table> + * <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr> + * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th rowspan="2">Sample use case(s)</th> </tr> + * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr> + * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app video / image processing.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>In-app viewfinder analysis.</td> </tr> + * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr> + * <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>In-app video / processing with preview.</td> </tr> + * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV }</td><td id="rb">{@code MAXIMUM}</td> <td>Standard Recording.</td> </tr> + * </table><br> + * </p> + * + * <p> For guaranteed concurrent stream configurations, MAXIMUM refers to the camera device's + * resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or + * 720p(1280X720) whichever is lower. </p> * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV} diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 55025f0411f9..9ee56a928d81 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -31,6 +31,9 @@ import android.hardware.camera2.impl.CameraDeviceImpl; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.legacy.CameraDeviceUserShim; import android.hardware.camera2.legacy.LegacyMetadataMapper; +import android.hardware.camera2.params.SessionConfiguration; +import android.hardware.camera2.utils.CameraIdAndSessionConfiguration; +import android.hardware.camera2.utils.ConcurrentCameraIdCombination; import android.os.Binder; import android.os.DeadObjectException; import android.os.Handler; @@ -40,6 +43,7 @@ import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.SystemProperties; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Size; import android.view.Display; @@ -48,6 +52,7 @@ import android.view.WindowManager; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -126,6 +131,66 @@ public final class CameraManager { } /** + * Return the list of combinations of currently connected camera devices identifiers, which + * support configuring camera device sessions concurrently. + * + * <p>The set of combinations may include camera devices that may be in use by other camera API + * clients.</p> + * + * <p>The set of combinations doesn't contain physical cameras that can only be used as + * part of a logical multi-camera device.</p> + * + * @return The set of combinations of currently connected camera devices, that may have + * sessions configured concurrently. The set of combinations will be empty if no such + * combinations are supported by the camera subsystem. + * + * @throws CameraAccessException if the camera device has been disconnected. + */ + @NonNull + public Set<Set<String>> getConcurrentStreamingCameraIds() throws CameraAccessException { + return CameraManagerGlobal.get().getConcurrentStreamingCameraIds(); + } + + /** + * Checks whether the provided set of camera devices and their corresponding + * {@link SessionConfiguration} can be configured concurrently. + * + * <p>This method performs a runtime check of the given {@link SessionConfiguration} and camera + * id combinations. The result confirms whether or not the passed session configurations can be + * successfully used to create camera capture sessions concurrently, on the given camera + * devices using {@link CameraDevice#createCaptureSession(SessionConfiguration)}. + * </p> + * + * <p>The method can be called at any point before, during and after active capture sessions. + * It will not impact normal camera behavior in any way and must complete significantly + * faster than creating a regular or constrained capture session.</p> + * + * <p>Although this method is faster than creating a new capture session, it is not intended + * to be used for exploring the entire space of supported concurrent stream combinations. The + * available mandatory concurrent stream combinations may be obtained by querying + * {@link #getCameraCharacteristics} for the key + * SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS. </p> + * + * <p>Note that session parameters will be ignored and calls to + * {@link SessionConfiguration#setSessionParameters} are not required.</p> + * + * @return {@code true} if the given combination of session configurations and corresponding + * camera ids are concurrently supported by the camera sub-system, + * {@code false} otherwise. + * + * @throws IllegalArgumentException if the set of camera devices provided is not a subset of + * those returned by getConcurrentStreamingCameraIds() + * @throws CameraAccessException if one of the camera devices queried is no longer connected. + */ + @RequiresPermission(android.Manifest.permission.CAMERA) + public boolean isConcurrentSessionConfigurationSupported( + @NonNull Map<String, SessionConfiguration> cameraIdAndSessionConfig) + throws CameraAccessException { + return CameraManagerGlobal.get().isConcurrentSessionConfigurationSupported( + cameraIdAndSessionConfig); + } + + /** * Register a callback to be notified about camera device availability. * * <p>Registering the same callback again will replace the handler with the @@ -336,8 +401,10 @@ public final class CameraManager { } catch (NumberFormatException e) { Log.e(TAG, "Failed to parse camera Id " + cameraId + " to integer"); } + boolean hasConcurrentStreams = + CameraManagerGlobal.get().cameraIdHasConcurrentStreamsLocked(cameraId); + info.setHasMandatoryConcurrentStreams(hasConcurrentStreams); info.setDisplaySize(displaySize); - characteristics = new CameraCharacteristics(info); } } catch (ServiceSpecificException e) { @@ -964,6 +1031,9 @@ public final class CameraManager { private final ArrayMap<String, ArrayList<String>> mUnavailablePhysicalDevices = new ArrayMap<String, ArrayList<String>>(); + private final Set<Set<String>> mConcurrentCameraIdCombinations = + new ArraySet<Set<String>>(); + // Registered availablility callbacks and their executors private final ArrayMap<AvailabilityCallback, Executor> mCallbackMap = new ArrayMap<AvailabilityCallback, Executor>(); @@ -1068,7 +1138,22 @@ public final class CameraManager { } catch (RemoteException e) { // Camera service is now down, leave mCameraService as null } + + try { + ConcurrentCameraIdCombination[] cameraIdCombinations = + cameraService.getConcurrentStreamingCameraIds(); + for (ConcurrentCameraIdCombination comb : cameraIdCombinations) { + mConcurrentCameraIdCombinations.add(comb.getConcurrentCameraIdCombination()); + } + } catch (ServiceSpecificException e) { + // Unexpected failure + throw new IllegalStateException("Failed to get concurrent camera id combinations", + e); + } catch (RemoteException e) { + // Camera service died in all probability + } } + private String[] extractCameraIdListLocked() { String[] cameraIds = null; int idCount = 0; @@ -1089,6 +1174,31 @@ public final class CameraManager { } return cameraIds; } + + private Set<Set<String>> extractConcurrentCameraIdListLocked() { + Set<Set<String>> concurrentCameraIds = new ArraySet<Set<String>>(); + for (Set<String> cameraIds : mConcurrentCameraIdCombinations) { + Set<String> extractedCameraIds = new ArraySet<String>(); + for (String cameraId : cameraIds) { + // if the camera id status is NOT_PRESENT or ENUMERATING; skip the device. + // TODO: Would a device status NOT_PRESENT ever be in the map ? it gets removed + // in the callback anyway. + Integer status = mDeviceStatus.get(cameraId); + if (status == null) { + // camera id not present + continue; + } + if (status == ICameraServiceListener.STATUS_ENUMERATING + || status == ICameraServiceListener.STATUS_NOT_PRESENT) { + continue; + } + extractedCameraIds.add(cameraId); + } + concurrentCameraIds.add(extractedCameraIds); + } + return concurrentCameraIds; + } + private static void sortCameraIds(String[] cameraIds) { // The sort logic must match the logic in // libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds @@ -1214,6 +1324,88 @@ public final class CameraManager { return cameraIds; } + public @NonNull Set<Set<String>> getConcurrentStreamingCameraIds() { + Set<Set<String>> concurrentStreamingCameraIds = null; + synchronized (mLock) { + // Try to make sure we have an up-to-date list of concurrent camera devices. + connectCameraServiceLocked(); + concurrentStreamingCameraIds = extractConcurrentCameraIdListLocked(); + } + // TODO: Some sort of sorting ? + return concurrentStreamingCameraIds; + } + + public boolean isConcurrentSessionConfigurationSupported( + @NonNull Map<String, SessionConfiguration> cameraIdsAndSessionConfigurations) + throws CameraAccessException { + + if (cameraIdsAndSessionConfigurations == null) { + throw new IllegalArgumentException("cameraIdsAndSessionConfigurations was null"); + } + + int size = cameraIdsAndSessionConfigurations.size(); + if (size == 0) { + throw new IllegalArgumentException("camera id and session combination is empty"); + } + + synchronized (mLock) { + // Go through all the elements and check if the camera ids are valid at least / + // belong to one of the combinations returned by getConcurrentStreamingCameraIds() + boolean subsetFound = false; + for (Set<String> combination : mConcurrentCameraIdCombinations) { + if (combination.containsAll(cameraIdsAndSessionConfigurations.keySet())) { + subsetFound = true; + } + } + if (!subsetFound) { + throw new IllegalArgumentException( + "The set of camera ids provided is not a subset of" + + "getConcurrentStreamingCameraIds"); + } + CameraIdAndSessionConfiguration [] cameraIdsAndConfigs = + new CameraIdAndSessionConfiguration[size]; + int i = 0; + for (Map.Entry<String, SessionConfiguration> pair : + cameraIdsAndSessionConfigurations.entrySet()) { + cameraIdsAndConfigs[i] = + new CameraIdAndSessionConfiguration(pair.getKey(), pair.getValue()); + i++; + } + try { + return mCameraService.isConcurrentSessionConfigurationSupported( + cameraIdsAndConfigs); + } catch (ServiceSpecificException e) { + throwAsPublicException(e); + } catch (RemoteException e) { + // Camera service died - act as if the camera was disconnected + throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED, + "Camera service is currently unavailable", e); + } + } + + return false; + } + + /** + * Helper function to find out if a camera id is in the set of combinations returned by + * getConcurrentStreamingCameraIds() + * @param cameraId the unique identifier of the camera device to query + * @return Whether the camera device was found in the set of combinations returned by + * getConcurrentStreamingCameraIds + */ + public boolean cameraIdHasConcurrentStreamsLocked(String cameraId) { + if (!mDeviceStatus.containsKey(cameraId)) { + Log.e(TAG, "cameraIdHasConcurrentStreamsLocked called on non existing camera id"); + return false; + } + for (Set<String> comb : mConcurrentCameraIdCombinations) { + if (comb.contains(cameraId)) { + return true; + } + } + return false; + } + public void setTorchMode(String cameraId, boolean enabled) throws CameraAccessException { synchronized(mLock) { @@ -1698,6 +1890,8 @@ public final class CameraManager { cameraId); } + mConcurrentCameraIdCombinations.clear(); + scheduleCameraServiceReconnectionLocked(); } } diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 3ae3d786af2a..aefe66fe5dec 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -621,6 +621,16 @@ public class CameraMetadataNative implements Parcelable { } }); sGetCommandMap.put( + CameraCharacteristics.SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { + return (T) metadata.getMandatoryConcurrentStreamCombinations(); + } + }); + + sGetCommandMap.put( CameraCharacteristics.CONTROL_MAX_REGIONS_AE.getNativeKey(), new GetCommand() { @Override @SuppressWarnings("unchecked") @@ -1247,7 +1257,8 @@ public class CameraMetadataNative implements Parcelable { return ret; } - private MandatoryStreamCombination[] getMandatoryStreamCombinations() { + private MandatoryStreamCombination[] getMandatoryStreamCombinationsHelper( + boolean getConcurrent) { int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES); ArrayList<Integer> caps = new ArrayList<Integer>(); caps.ensureCapacity(capabilities.length); @@ -1257,7 +1268,13 @@ public class CameraMetadataNative implements Parcelable { int hwLevel = getBase(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); MandatoryStreamCombination.Builder build = new MandatoryStreamCombination.Builder( mCameraId, hwLevel, mDisplaySize, caps, getStreamConfigurationMap()); - List<MandatoryStreamCombination> combs = build.getAvailableMandatoryStreamCombinations(); + + List<MandatoryStreamCombination> combs = null; + if (getConcurrent) { + combs = build.getAvailableMandatoryConcurrentStreamCombinations(); + } else { + combs = build.getAvailableMandatoryStreamCombinations(); + } if ((combs != null) && (!combs.isEmpty())) { MandatoryStreamCombination[] combArray = new MandatoryStreamCombination[combs.size()]; combArray = combs.toArray(combArray); @@ -1267,6 +1284,17 @@ public class CameraMetadataNative implements Parcelable { return null; } + private MandatoryStreamCombination[] getMandatoryConcurrentStreamCombinations() { + if (!mHasMandatoryConcurrentStreams) { + return null; + } + return getMandatoryStreamCombinationsHelper(true); + } + + private MandatoryStreamCombination[] getMandatoryStreamCombinations() { + return getMandatoryStreamCombinationsHelper(false); + } + private StreamConfigurationMap getStreamConfigurationMap() { StreamConfiguration[] configurations = getBase( CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS); @@ -1614,6 +1642,7 @@ public class CameraMetadataNative implements Parcelable { } private int mCameraId = -1; + private boolean mHasMandatoryConcurrentStreams = false; private Size mDisplaySize = new Size(0, 0); /** @@ -1628,6 +1657,18 @@ public class CameraMetadataNative implements Parcelable { } /** + * Set the current camera Id. + * + * @param hasMandatoryConcurrentStreams whether the metadata advertises mandatory concurrent + * streams. + * + * @hide + */ + public void setHasMandatoryConcurrentStreams(boolean hasMandatoryConcurrentStreams) { + mHasMandatoryConcurrentStreams = hasMandatoryConcurrentStreams; + } + + /** * Set the current display size. * * @param displaySize The current display size. @@ -1682,6 +1723,7 @@ public class CameraMetadataNative implements Parcelable { public void swap(CameraMetadataNative other) { nativeSwap(other); mCameraId = other.mCameraId; + mHasMandatoryConcurrentStreams = other.mHasMandatoryConcurrentStreams; mDisplaySize = other.mDisplaySize; } diff --git a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java index 23f18a80caf8..41e1443d6866 100644 --- a/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java +++ b/core/java/android/hardware/camera2/params/MandatoryStreamCombination.java @@ -16,30 +16,27 @@ package android.hardware.camera2.params; -import static com.android.internal.util.Preconditions.*; import static android.hardware.camera2.params.StreamConfigurationMap.checkArgumentFormat; -import android.annotation.IntRange; +import static com.android.internal.util.Preconditions.*; + import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.Context; import android.graphics.ImageFormat; import android.graphics.ImageFormat.Format; import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraCharacteristics.Key; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.HashCodeHelpers; -import android.graphics.PixelFormat; import android.media.CamcorderProfile; -import android.util.Size; import android.util.Log; import android.util.Pair; +import android.util.Size; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -200,7 +197,6 @@ public final class MandatoryStreamCombination { mDescription = description; mIsReprocessable = isReprocessable; } - /** * Get the mandatory stream combination description. * @@ -271,7 +267,7 @@ public final class MandatoryStreamCombination { mStreamsInformation.hashCode()); } - private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM } + private static enum SizeThreshold { VGA, PREVIEW, RECORD, MAXIMUM, s720p } private static enum ReprocessType { NONE, PRIVATE, YUV } private static final class StreamTemplate { public int mFormat; @@ -653,6 +649,27 @@ public final class MandatoryStreamCombination { /*reprocessType*/ ReprocessType.YUV), }; + private static StreamCombinationTemplate sConcurrentStreamCombinations[] = { + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p) }, + "In-app video / image processing"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p) }, + "preview / preview to GPU"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)}, + "In-app video / image processing with preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p), + new StreamTemplate(ImageFormat.YUV_420_888, SizeThreshold.s720p)}, + "In-app video / image processing with preview"), + new StreamCombinationTemplate(new StreamTemplate [] { + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p), + new StreamTemplate(ImageFormat.PRIVATE, SizeThreshold.s720p)}, + "Standard Recording"), + }; + /** * Helper builder class to generate a list of available mandatory stream combinations. * @hide @@ -687,6 +704,64 @@ public final class MandatoryStreamCombination { } /** + * Retrieve a list of all available mandatory concurrent stream combinations. + * This method should only be called for devices which are listed in combinations returned + * by CameraManager.getConcurrentStreamingCameraIds. + * + * @return a non-modifiable list of supported mandatory concurrent stream combinations. + */ + public @NonNull List<MandatoryStreamCombination> + getAvailableMandatoryConcurrentStreamCombinations() { + // Since concurrent streaming support is optional, we mandate these stream + // combinations regardless of camera device capabilities. + if (!isColorOutputSupported()) { + Log.v(TAG, "Device is not backward compatible!"); + throw new IllegalArgumentException("Camera device which is not BACKWARD_COMPATIBLE" + + " cannot have mandatory concurrent streams"); + } + Size size720p = new Size(1280, 720); + + ArrayList<MandatoryStreamCombination> availableConcurrentStreamCombinations = + new ArrayList<MandatoryStreamCombination>(); + availableConcurrentStreamCombinations.ensureCapacity( + sConcurrentStreamCombinations.length); + for (StreamCombinationTemplate combTemplate : sConcurrentStreamCombinations) { + ArrayList<MandatoryStreamInformation> streamsInfo = + new ArrayList<MandatoryStreamInformation>(); + streamsInfo.ensureCapacity(combTemplate.mStreamTemplates.length); + for (StreamTemplate template : combTemplate.mStreamTemplates) { + MandatoryStreamInformation streamInfo; + List<Size> sizes = new ArrayList<Size>(); + Size sizeChosen = + getMinSize(size720p, + getMaxSize(mStreamConfigMap.getOutputSizes(template.mFormat))); + sizes.add(sizeChosen); + try { + streamInfo = new MandatoryStreamInformation(sizes, template.mFormat); + } catch (IllegalArgumentException e) { + String cause = "No available sizes found for format: " + template.mFormat + + " size threshold: " + template.mSizeThreshold + " combination: " + + combTemplate.mDescription; + throw new RuntimeException(cause, e); + } + streamsInfo.add(streamInfo); + } + + MandatoryStreamCombination streamCombination; + try { + streamCombination = new MandatoryStreamCombination(streamsInfo, + combTemplate.mDescription, /*isReprocess*/false); + } catch (IllegalArgumentException e) { + String cause = "No stream information for mandatory combination: " + + combTemplate.mDescription; + throw new RuntimeException(cause, e); + } + availableConcurrentStreamCombinations.add(streamCombination); + } + return Collections.unmodifiableList(availableConcurrentStreamCombinations); + } + + /** * Retrieve a list of all available mandatory stream combinations. * * @return a non-modifiable list of supported mandatory stream combinations or @@ -965,6 +1040,18 @@ public final class MandatoryStreamCombination { } /** + * Return the lower size + */ + public static @Nullable Size getMinSize(Size a, Size b) { + if (a == null || b == null) { + throw new IllegalArgumentException("sizes was empty"); + } + if (a.getWidth() * a.getHeight() < b.getHeight() * b.getWidth()) { + return a; + } + return b; + } + /** * Get the largest size by area. * * @param sizes an array of sizes, must have at least 1 element diff --git a/core/java/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.java b/core/java/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.java new file mode 100644 index 000000000000..cdc037cbd020 --- /dev/null +++ b/core/java/android/hardware/camera2/utils/CameraIdAndSessionConfiguration.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2.utils; + +import android.annotation.NonNull; +import android.hardware.camera2.params.SessionConfiguration; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * CameraIdAndSessionConfiguration + * + * Includes the pair of a cameraId and its corresponding SessionConfiguration, to be used with + * ICameraService.isConcurrentSessionConfigurationSupported. + * @hide + */ +public class CameraIdAndSessionConfiguration implements Parcelable { + + private String mCameraId; + private SessionConfiguration mSessionConfiguration; + + public CameraIdAndSessionConfiguration(@NonNull String cameraId, + @NonNull SessionConfiguration sessionConfiguration) { + mCameraId = cameraId; + mSessionConfiguration = sessionConfiguration; + } + + public static final @NonNull + Parcelable.Creator<CameraIdAndSessionConfiguration> CREATOR = + new Parcelable.Creator<CameraIdAndSessionConfiguration>() { + @Override + public CameraIdAndSessionConfiguration createFromParcel(Parcel in) { + return new CameraIdAndSessionConfiguration(in); + } + + @Override + public CameraIdAndSessionConfiguration[] newArray(int size) { + return new CameraIdAndSessionConfiguration[size]; + } + }; + + private CameraIdAndSessionConfiguration(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mCameraId); + mSessionConfiguration.writeToParcel(dest, flags); + } + + /** + * helper for CREATOR + */ + public void readFromParcel(Parcel in) { + mCameraId = in.readString(); + mSessionConfiguration = SessionConfiguration.CREATOR.createFromParcel(in); + } + + public @NonNull String getCameraId() { + return mCameraId; + } + + public @NonNull SessionConfiguration getSessionConfiguration() { + return mSessionConfiguration; + } +} diff --git a/core/java/android/hardware/camera2/utils/ConcurrentCameraIdCombination.java b/core/java/android/hardware/camera2/utils/ConcurrentCameraIdCombination.java new file mode 100644 index 000000000000..8f4d6365f05e --- /dev/null +++ b/core/java/android/hardware/camera2/utils/ConcurrentCameraIdCombination.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2.utils; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.HashSet; +import java.util.Set; + +/** + * ConcurrentCameraIdCombination + * + * Includes a list of camera ids that may have sessions configured concurrently. + * @hide + */ +public class ConcurrentCameraIdCombination implements Parcelable { + + private Set<String> mConcurrentCameraIds = new HashSet<>(); + + public static final @NonNull + Parcelable.Creator<ConcurrentCameraIdCombination> CREATOR = + new Parcelable.Creator<ConcurrentCameraIdCombination>() { + @Override + public ConcurrentCameraIdCombination createFromParcel(Parcel in) { + return new ConcurrentCameraIdCombination(in); + } + + @Override + public ConcurrentCameraIdCombination[] newArray(int size) { + return new ConcurrentCameraIdCombination[size]; + } + }; + + private ConcurrentCameraIdCombination(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mConcurrentCameraIds.size()); + for (String cameraId : mConcurrentCameraIds) { + dest.writeString(cameraId); + } + } + + /** + * helper for CREATOR + */ + public void readFromParcel(Parcel in) { + mConcurrentCameraIds.clear(); + int cameraCombinationSize = in.readInt(); + if (cameraCombinationSize < 0) { + throw new RuntimeException("cameraCombinationSize " + cameraCombinationSize + + " should not be negative"); + } + for (int i = 0; i < cameraCombinationSize; i++) { + String cameraId = in.readString(); + if (cameraId == null) { + throw new RuntimeException("Failed to read camera id from Parcel"); + } + mConcurrentCameraIds.add(cameraId); + } + } + + /** + * Get this concurrent camera id combination. + */ + public Set<String> getConcurrentCameraIdCombination() { + return mConcurrentCameraIds; + } +} diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java index 13122d249b23..6412a0ce7219 100644 --- a/core/java/android/hardware/display/BrightnessConfiguration.java +++ b/core/java/android/hardware/display/BrightnessConfiguration.java @@ -61,7 +61,7 @@ public final class BrightnessConfiguration implements Parcelable { private static final String ATTR_MODEL_LOWER_BOUND = "model-lower-bound"; private static final String ATTR_MODEL_UPPER_BOUND = "model-upper-bound"; /** - * Returned from {@link #getShortTermModelTimeout()} if no timeout has been set. + * Returned from {@link #getShortTermModelTimeoutMillis()} if no timeout has been set. * In this case the device will use the default timeout available in the * {@link BrightnessConfiguration} returned from * {@link DisplayManager#getDefaultBrightnessConfiguration()}. @@ -160,7 +160,7 @@ public final class BrightnessConfiguration implements Parcelable { * {@link #getShortTermModelUpperLuxMultiplier()} to decide whether to keep any adjustment * the user has made to adaptive brightness. */ - public long getShortTermModelTimeout() { + public long getShortTermModelTimeoutMillis() { return mShortTermModelTimeout; } @@ -326,7 +326,7 @@ public final class BrightnessConfiguration implements Parcelable { builder.setDescription(description); final boolean shouldCollectColorSamples = in.readBoolean(); builder.setShouldCollectColorSamples(shouldCollectColorSamples); - builder.setShortTermModelTimeout(in.readLong()); + builder.setShortTermModelTimeoutMillis(in.readLong()); builder.setShortTermModelLowerLuxMultiplier(in.readFloat()); builder.setShortTermModelUpperLuxMultiplier(in.readFloat()); return builder.build(); @@ -487,7 +487,7 @@ public final class BrightnessConfiguration implements Parcelable { builder.addCorrectionByCategory(category, correction); } builder.setShouldCollectColorSamples(shouldCollectColorSamples); - builder.setShortTermModelTimeout(shortTermModelTimeout); + builder.setShortTermModelTimeoutMillis(shortTermModelTimeout); builder.setShortTermModelLowerLuxMultiplier(shortTermModelLowerLuxMultiplier); builder.setShortTermModelUpperLuxMultiplier(shortTermModelUpperLuxMultiplier); return builder.build(); @@ -673,8 +673,8 @@ public final class BrightnessConfiguration implements Parcelable { * adjustment the user has made to adaptive brightness. */ @NonNull - public Builder setShortTermModelTimeout(long shortTermModelTimeout) { - mShortTermModelTimeout = shortTermModelTimeout; + public Builder setShortTermModelTimeoutMillis(long shortTermModelTimeoutMillis) { + mShortTermModelTimeout = shortTermModelTimeoutMillis; return this; } diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index fd015b4fe52c..a3899b705c1b 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -16,7 +16,10 @@ package android.net; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; @@ -24,12 +27,15 @@ import android.os.Message; import android.os.RemoteException; import java.util.ArrayList; +import java.util.Objects; /** * A class representing the IP configuration of the Ethernet network. * * @hide */ +@SystemApi +@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; @@ -37,7 +43,7 @@ public class EthernetManager { private final Context mContext; private final IEthernetManager mService; - private final Handler mHandler = new Handler() { + private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == MSG_AVAILABILITY_CHANGED) { @@ -60,12 +66,14 @@ public class EthernetManager { /** * A listener interface to receive notification on changes in Ethernet. + * @hide */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. + * @hide */ @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); @@ -76,6 +84,7 @@ public class EthernetManager { * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. + * @hide */ public EthernetManager(Context context, IEthernetManager service) { mContext = context; @@ -85,6 +94,7 @@ public class EthernetManager { /** * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + * @hide */ @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { @@ -97,6 +107,7 @@ public class EthernetManager { /** * Set Ethernet configuration. + * @hide */ @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { @@ -109,6 +120,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. + * @hide */ @UnsupportedAppUsage public boolean isAvailable() { @@ -119,6 +131,7 @@ public class EthernetManager { * Indicates whether the system has given interface. * * @param iface Ethernet interface name + * @hide */ @UnsupportedAppUsage public boolean isAvailable(String iface) { @@ -133,6 +146,7 @@ public class EthernetManager { * Adds a listener. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void addListener(Listener listener) { @@ -151,6 +165,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. + * @hide */ @UnsupportedAppUsage public String[] getAvailableInterfaces() { @@ -165,6 +180,7 @@ public class EthernetManager { * Removes a listener. * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void removeListener(Listener listener) { @@ -180,4 +196,78 @@ public class EthernetManager { } } } + + /** + * A request for a tethered interface. + */ + public static class TetheredInterfaceRequest { + private final IEthernetManager mService; + private final ITetheredInterfaceCallback mCb; + + private TetheredInterfaceRequest(@NonNull IEthernetManager service, + @NonNull ITetheredInterfaceCallback cb) { + this.mService = service; + this.mCb = cb; + } + + /** + * Release the request, causing the interface to revert back from tethering mode if there + * is no other requestor. + */ + public void release() { + try { + mService.releaseTetheredInterface(mCb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + } + + /** + * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. + */ + public interface TetheredInterfaceCallback { + /** + * Called when the tethered interface is available. + * @param iface The name of the interface. + */ + void onAvailable(@NonNull String iface); + + /** + * Called when the tethered interface is now unavailable. + */ + void onUnavailable(); + } + + /** + * Request a tethered interface in tethering mode. + * + * <p>When this method is called and there is at least one ethernet interface available, the + * system will designate one to act as a tethered interface. If there is already a tethered + * interface, the existing interface will be used. + * @param callback A callback to be called once the request has been fulfilled. + */ + @NonNull + public TetheredInterfaceRequest requestTetheredInterface( + @NonNull TetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "Callback must be non-null"); + final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { + @Override + public void onAvailable(String iface) { + callback.onAvailable(iface); + } + + @Override + public void onUnavailable() { + callback.onUnavailable(); + } + }; + + try { + mService.requestTetheredInterface(cbInternal); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return new TetheredInterfaceRequest(mService, cbInternal); + } } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 94960b51d329..ccc6e352098f 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; /** * Interface that answers queries about, and allows changing @@ -32,4 +33,6 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void requestTetheredInterface(in ITetheredInterfaceCallback callback); + void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl new file mode 100644 index 000000000000..e3d075988c8a --- /dev/null +++ b/core/java/android/net/ITetheredInterfaceCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 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; + +/** @hide */ +interface ITetheredInterfaceCallback { + void onAvailable(in String iface); + void onUnavailable(); +}
\ No newline at end of file diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java index fb36e6f6978f..228548ad7802 100644 --- a/core/java/android/os/HwParcel.java +++ b/core/java/android/os/HwParcel.java @@ -38,6 +38,7 @@ import java.util.Arrays; public class HwParcel { private static final String TAG = "HwParcel"; + /** @hide */ @IntDef(prefix = { "STATUS_" }, value = { STATUS_SUCCESS, }) diff --git a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java index 664b6c87d339..016cc2f3cdad 100644 --- a/core/java/android/os/connectivity/WifiActivityEnergyInfo.java +++ b/core/java/android/os/connectivity/WifiActivityEnergyInfo.java @@ -16,7 +16,9 @@ package android.os.connectivity; +import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.ActivityThread; @@ -37,14 +39,20 @@ import java.lang.annotation.RetentionPolicy; */ @SystemApi public final class WifiActivityEnergyInfo implements Parcelable { - private long mTimeSinceBootMillis; + @ElapsedRealtimeLong + private final long mTimeSinceBootMillis; @StackState - private int mStackState; - private long mControllerTxDurationMillis; - private long mControllerRxDurationMillis; - private long mControllerScanDurationMillis; - private long mControllerIdleDurationMillis; - private long mControllerEnergyUsedMicroJoules; + private final int mStackState; + @IntRange(from = 0) + private final long mControllerTxDurationMillis; + @IntRange(from = 0) + private final long mControllerRxDurationMillis; + @IntRange(from = 0) + private final long mControllerScanDurationMillis; + @IntRange(from = 0) + private final long mControllerIdleDurationMillis; + @IntRange(from = 0) + private final long mControllerEnergyUsedMicroJoules; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -67,7 +75,7 @@ public final class WifiActivityEnergyInfo implements Parcelable { /** * Constructor. * - * @param timeSinceBootMillis the time since boot, in milliseconds. + * @param timeSinceBootMillis the elapsed real time since boot, in milliseconds. * @param stackState The current state of the Wifi Stack. One of {@link #STACK_STATE_INVALID}, * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING}, * or {@link #STACK_STATE_STATE_IDLE}. @@ -78,23 +86,27 @@ public final class WifiActivityEnergyInfo implements Parcelable { * receiving. */ public WifiActivityEnergyInfo( - long timeSinceBootMillis, + @ElapsedRealtimeLong long timeSinceBootMillis, @StackState int stackState, - long txDurationMillis, - long rxDurationMillis, - long scanDurationMillis, - long idleDurationMillis) { - mTimeSinceBootMillis = timeSinceBootMillis; - mStackState = stackState; - mControllerTxDurationMillis = txDurationMillis; - mControllerRxDurationMillis = rxDurationMillis; - mControllerScanDurationMillis = scanDurationMillis; - mControllerIdleDurationMillis = idleDurationMillis; - + @IntRange(from = 0) long txDurationMillis, + @IntRange(from = 0) long rxDurationMillis, + @IntRange(from = 0) long scanDurationMillis, + @IntRange(from = 0) long idleDurationMillis) { + + this(timeSinceBootMillis, + stackState, + txDurationMillis, + rxDurationMillis, + scanDurationMillis, + idleDurationMillis, + calculateEnergyMicroJoules(txDurationMillis, rxDurationMillis, idleDurationMillis)); + } + + private static long calculateEnergyMicroJoules( + long txDurationMillis, long rxDurationMillis, long idleDurationMillis) { final Context context = ActivityThread.currentActivityThread().getSystemContext(); if (context == null) { - mControllerEnergyUsedMicroJoules = 0L; - return; + return 0L; } // Calculate energy used using PowerProfile. PowerProfile powerProfile = new PowerProfile(context); @@ -106,10 +118,28 @@ public final class WifiActivityEnergyInfo implements Parcelable { PowerProfile.POWER_WIFI_CONTROLLER_TX); final double voltage = powerProfile.getAveragePower( PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; - final long energyUsedMicroJoules = (long) ((mControllerTxDurationMillis * txCurrent - + mControllerRxDurationMillis * rxCurrent - + mControllerIdleDurationMillis * rxIdleCurrent) + + return (long) ((txDurationMillis * txCurrent + + rxDurationMillis * rxCurrent + + idleDurationMillis * rxIdleCurrent) * voltage); + } + + /** @hide */ + public WifiActivityEnergyInfo( + @ElapsedRealtimeLong long timeSinceBootMillis, + @StackState int stackState, + @IntRange(from = 0) long txDurationMillis, + @IntRange(from = 0) long rxDurationMillis, + @IntRange(from = 0) long scanDurationMillis, + @IntRange(from = 0) long idleDurationMillis, + @IntRange(from = 0) long energyUsedMicroJoules) { + mTimeSinceBootMillis = timeSinceBootMillis; + mStackState = stackState; + mControllerTxDurationMillis = txDurationMillis; + mControllerRxDurationMillis = rxDurationMillis; + mControllerScanDurationMillis = scanDurationMillis; + mControllerIdleDurationMillis = idleDurationMillis; mControllerEnergyUsedMicroJoules = energyUsedMicroJoules; } @@ -158,16 +188,12 @@ public final class WifiActivityEnergyInfo implements Parcelable { return 0; } - /** Get the timestamp (milliseconds since boot) of record creation. */ + /** Get the timestamp (elapsed real time milliseconds since boot) of record creation. */ + @ElapsedRealtimeLong public long getTimeSinceBootMillis() { return mTimeSinceBootMillis; } - /** Set the timestamp (milliseconds since boot) of record creation. */ - public void setTimeSinceBootMillis(long timeSinceBootMillis) { - mTimeSinceBootMillis = timeSinceBootMillis; - } - /** * Get the Wifi stack reported state. One of {@link #STACK_STATE_INVALID}, * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING}, @@ -178,66 +204,40 @@ public final class WifiActivityEnergyInfo implements Parcelable { return mStackState; } - /** - * Set the Wifi stack reported state. One of {@link #STACK_STATE_INVALID}, - * {@link #STACK_STATE_STATE_ACTIVE}, {@link #STACK_STATE_STATE_SCANNING}, - * {@link #STACK_STATE_STATE_IDLE}. - */ - public void setStackState(@StackState int stackState) { - mStackState = stackState; - } - /** Get the Wifi transmission duration, in milliseconds. */ + @IntRange(from = 0) public long getControllerTxDurationMillis() { return mControllerTxDurationMillis; } - /** Set the Wifi transmission duration, in milliseconds. */ - public void setControllerTxDurationMillis(long controllerTxDurationMillis) { - mControllerTxDurationMillis = controllerTxDurationMillis; - } - /** Get the Wifi receive duration, in milliseconds. */ + @IntRange(from = 0) public long getControllerRxDurationMillis() { return mControllerRxDurationMillis; } - /** Set the Wifi receive duration, in milliseconds. */ - public void setControllerRxDurationMillis(long controllerRxDurationMillis) { - mControllerRxDurationMillis = controllerRxDurationMillis; - } - /** Get the Wifi scan duration, in milliseconds. */ + @IntRange(from = 0) public long getControllerScanDurationMillis() { return mControllerScanDurationMillis; } - /** Set the Wifi scan duration, in milliseconds. */ - public void setControllerScanDurationMillis(long controllerScanDurationMillis) { - mControllerScanDurationMillis = controllerScanDurationMillis; - } - /** Get the Wifi idle duration, in milliseconds. */ + @IntRange(from = 0) public long getControllerIdleDurationMillis() { return mControllerIdleDurationMillis; } - /** Set the Wifi idle duration, in milliseconds. */ - public void setControllerIdleDurationMillis(long controllerIdleDurationMillis) { - mControllerIdleDurationMillis = controllerIdleDurationMillis; - } - /** Get the energy consumed by Wifi, in microjoules. */ + @IntRange(from = 0) public long getControllerEnergyUsedMicroJoules() { return mControllerEnergyUsedMicroJoules; } - /** Set the energy consumed by Wifi, in microjoules. */ - public void setControllerEnergyUsedMicroJoules(long controllerEnergyUsedMicroJoules) { - mControllerEnergyUsedMicroJoules = controllerEnergyUsedMicroJoules; - } - - /** Returns true if the record is valid, false otherwise. */ + /** + * Returns true if the record is valid, false otherwise. + * @hide + */ public boolean isValid() { return mControllerTxDurationMillis >= 0 && mControllerRxDurationMillis >= 0 diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java index 36e2d1f6b251..ac2532dcea7d 100644 --- a/core/java/android/service/contentcapture/ContentCaptureService.java +++ b/core/java/android/service/contentcapture/ContentCaptureService.java @@ -544,11 +544,14 @@ public abstract class ContentCaptureService extends Service { Preconditions.checkNotNull(adapter); Preconditions.checkNotNull(executor); - DataShareReadAdapterDelegate delegate = - new DataShareReadAdapterDelegate(executor, adapter); + ICancellationSignal cancellationSignalTransport = + CancellationSignal.createTransport(); + + DataShareReadAdapterDelegate delegate = new DataShareReadAdapterDelegate( + executor, cancellationSignalTransport, adapter); try { - callback.accept(delegate); + callback.accept(cancellationSignalTransport, delegate); } catch (RemoteException e) { Slog.e(TAG, "Failed to accept data sharing", e); } @@ -655,12 +658,16 @@ public abstract class ContentCaptureService extends Service { private final Object mLock = new Object(); private final WeakReference<DataShareReadAdapter> mAdapterReference; private final WeakReference<Executor> mExecutorReference; + private final WeakReference<ICancellationSignal> mCancellationSignalReference; - DataShareReadAdapterDelegate(Executor executor, DataShareReadAdapter adapter) { + DataShareReadAdapterDelegate(Executor executor, + ICancellationSignal cancellationSignalTransport, DataShareReadAdapter adapter) { Preconditions.checkNotNull(executor); + Preconditions.checkNotNull(cancellationSignalTransport); Preconditions.checkNotNull(adapter); mExecutorReference = new WeakReference<>(executor); + mCancellationSignalReference = new WeakReference<>(cancellationSignalTransport); mAdapterReference = new WeakReference<>(adapter); } @@ -668,7 +675,17 @@ public abstract class ContentCaptureService extends Service { public void start(ParcelFileDescriptor fd, ICancellationSignal remoteCancellationSignal) throws RemoteException { synchronized (mLock) { - CancellationSignal cancellationSignal = new CancellationSignal(); + ICancellationSignal serverControlledCancellationSignal = + mCancellationSignalReference.get(); + + if (serverControlledCancellationSignal == null) { + Slog.w(TAG, "Can't execute onStart(), reference to cancellation signal has " + + "been GC'ed"); + return; + } + + CancellationSignal cancellationSignal = + CancellationSignal.fromTransport(serverControlledCancellationSignal); cancellationSignal.setRemote(remoteCancellationSignal); executeAdapterMethodLocked( diff --git a/core/java/android/service/contentcapture/DataShareReadAdapter.java b/core/java/android/service/contentcapture/DataShareReadAdapter.java index d9350ba5d774..ca6820110ea9 100644 --- a/core/java/android/service/contentcapture/DataShareReadAdapter.java +++ b/core/java/android/service/contentcapture/DataShareReadAdapter.java @@ -40,8 +40,7 @@ public interface DataShareReadAdapter { void onStart(@NonNull ParcelFileDescriptor fd, @NonNull CancellationSignal cancellationSignal); /** - * Signals that the session failed to start or terminated unsuccessfully (e.g. due to a - * timeout). + * Signals that the session failed to start or terminated unsuccessfully. **/ void onError(int errorCode); } diff --git a/core/java/android/service/contentcapture/IDataShareCallback.aidl b/core/java/android/service/contentcapture/IDataShareCallback.aidl index c1aa1bb7dcb5..d972adadb53c 100644 --- a/core/java/android/service/contentcapture/IDataShareCallback.aidl +++ b/core/java/android/service/contentcapture/IDataShareCallback.aidl @@ -16,10 +16,11 @@ package android.service.contentcapture; +import android.os.ICancellationSignal; import android.service.contentcapture.IDataShareReadAdapter; /** @hide */ oneway interface IDataShareCallback { - void accept(in IDataShareReadAdapter adapter); + void accept(in ICancellationSignal cancellationSignal, in IDataShareReadAdapter adapter); void reject(); } diff --git a/core/java/android/service/controls/TokenProvider.aidl b/core/java/android/service/controls/TokenProvider.aidl new file mode 100644 index 000000000000..8f4b7953f659 --- /dev/null +++ b/core/java/android/service/controls/TokenProvider.aidl @@ -0,0 +1,7 @@ +package android.service.controls; + +/** @hide */ +interface TokenProvider { + void setAuthToken(String token); + String getAccountName(); +}
\ No newline at end of file diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index 7815864ddfe9..26c831428f1c 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -1259,6 +1259,7 @@ public abstract class TextToSpeechService extends Service { @Override public IBinder onBind(Intent intent) { if (TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE.equals(intent.getAction())) { + Binder.allowBlocking(mBinder.asBinder()); return mBinder; } return null; diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 14390f1c209b..e1f1581c53bc 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -558,12 +558,6 @@ interface IWindowManager boolean isWindowTraceEnabled(); /** - * Requests that the WindowManager sends - * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity. - */ - void requestUserActivityNotification(); - - /** * Notify WindowManager that it should not override the info in DisplayManager for the specified * display. This can disable letter- or pillar-boxing applied in DisplayManager when the metrics * of the logical display reported from WindowManager do not correspond to the metrics of the diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 55c298e2a92b..a6450a10561b 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2459,6 +2459,7 @@ public interface WindowManager extends ViewManager { * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} * will be used. */ + @ActivityInfo.ScreenOrientation public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; /** diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java index a22f5a576ab6..492ab6f8a3d5 100644 --- a/core/java/android/view/WindowManagerPolicyConstants.java +++ b/core/java/android/view/WindowManagerPolicyConstants.java @@ -66,12 +66,6 @@ public interface WindowManagerPolicyConstants { String NAV_BAR_MODE_GESTURAL_OVERLAY = "com.android.internal.systemui.navbar.gestural"; /** - * Broadcast sent when a user activity is detected. - */ - String ACTION_USER_ACTIVITY_NOTIFICATION = - "android.intent.action.USER_ACTIVITY_NOTIFICATION"; - - /** * Sticky broadcast of the current HDMI plugged state. */ String ACTION_HDMI_PLUGGED = "android.intent.action.HDMI_PLUGGED"; diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 81c83834098c..cede3b5cf9fe 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -35,6 +35,7 @@ import android.os.Binder; import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; +import android.os.ICancellationSignal; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -655,9 +656,12 @@ public final class ContentCaptureManager { Preconditions.checkNotNull(dataShareWriteAdapter); Preconditions.checkNotNull(executor); + ICancellationSignal cancellationSignalTransport = CancellationSignal.createTransport(); + try { - mService.shareData(request, - new DataShareAdapterDelegate(executor, dataShareWriteAdapter)); + mService.shareData(request, cancellationSignalTransport, + new DataShareAdapterDelegate(executor, + cancellationSignalTransport, dataShareWriteAdapter)); } catch (RemoteException e) { e.rethrowFromSystemServer(); } @@ -715,20 +719,30 @@ public final class ContentCaptureManager { private final WeakReference<DataShareWriteAdapter> mAdapterReference; private final WeakReference<Executor> mExecutorReference; + private final WeakReference<ICancellationSignal> mCancellationSignal; - private DataShareAdapterDelegate(Executor executor, DataShareWriteAdapter adapter) { + private DataShareAdapterDelegate(Executor executor, + ICancellationSignal cancellationSignalTransport, DataShareWriteAdapter adapter) { Preconditions.checkNotNull(executor); + Preconditions.checkNotNull(cancellationSignalTransport); Preconditions.checkNotNull(adapter); mExecutorReference = new WeakReference<>(executor); mAdapterReference = new WeakReference<>(adapter); + mCancellationSignal = new WeakReference<>(cancellationSignalTransport); } @Override public void write(ParcelFileDescriptor destination) throws RemoteException { - // TODO(b/148264965): implement this. - CancellationSignal cancellationSignal = new CancellationSignal(); + ICancellationSignal cancellationSignalTransport = mCancellationSignal.get(); + if (cancellationSignalTransport == null) { + Slog.w(TAG, "Can't execute write(), reference to cancellation signal has been " + + "GC'ed"); + } + CancellationSignal cancellationSignal = + CancellationSignal.fromTransport(cancellationSignalTransport); + executeAdapterMethodLocked(adapter -> adapter.onWrite(destination, cancellationSignal), "onWrite"); } diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl index e8d85ac69907..5217e68eac50 100644 --- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl +++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl @@ -23,6 +23,7 @@ import android.view.contentcapture.DataRemovalRequest; import android.view.contentcapture.DataShareRequest; import android.view.contentcapture.IDataShareWriteAdapter; import android.os.IBinder; +import android.os.ICancellationSignal; import com.android.internal.os.IResultReceiver; @@ -68,7 +69,8 @@ oneway interface IContentCaptureManager { /** * Requests sharing of a binary data with the content capture service. */ - void shareData(in DataShareRequest request, in IDataShareWriteAdapter adapter); + void shareData(in DataShareRequest request, in ICancellationSignal cancellationSignal, + in IDataShareWriteAdapter adapter); /** * Returns whether the content capture feature is enabled for the calling user. diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index 42d7892eeffb..c8a7c079994c 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -17,6 +17,7 @@ package android.widget; import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkState; import android.annotation.IntDef; import android.annotation.NonNull; @@ -24,6 +25,9 @@ import android.annotation.Nullable; import android.annotation.StringRes; import android.app.INotificationManager; import android.app.ITransientNotification; +import android.app.ITransientNotificationCallback; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; @@ -105,15 +109,45 @@ public class Toast { */ public static final int LENGTH_LONG = 1; + /** + * Text toasts will be rendered by SystemUI instead of in-app, so apps can't circumvent + * background custom toast restrictions. + * + * TODO(b/144152069): Add @EnabledAfter(Q) to target R+ after assessing impact on dogfood + */ + @ChangeId + // @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) + private static final long CHANGE_TEXT_TOASTS_IN_THE_SYSTEM = 147798919L; + + private final Binder mToken; private final Context mContext; + private final Handler mHandler; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) final TN mTN; @UnsupportedAppUsage int mDuration; - View mNextView; - // TODO(b/128611929): Remove this and check for null view when toast creation is in the system - boolean mIsCustomToast = false; + + /** + * This is also passed to {@link TN} object, where it's also accessed with itself as its own + * lock. + */ + @GuardedBy("mCallbacks") + private final List<Callback> mCallbacks; + + /** + * View to be displayed, in case this is a custom toast (e.g. not created with {@link + * #makeText(Context, int, int)} or its variants). + */ + @Nullable + private View mNextView; + + /** + * Text to be shown, in case this is NOT a custom toast (e.g. created with {@link + * #makeText(Context, int, int)} or its variants). + */ + @Nullable + private CharSequence mText; /** * Construct an empty Toast object. You must call {@link #setView} before you @@ -133,19 +167,34 @@ public class Toast { public Toast(@NonNull Context context, @Nullable Looper looper) { mContext = context; mToken = new Binder(); - mTN = new TN(context.getPackageName(), mToken, looper); + looper = getLooper(looper); + mHandler = new Handler(looper); + mCallbacks = new ArrayList<>(); + mTN = new TN(context.getPackageName(), mToken, mCallbacks, looper); mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset); mTN.mGravity = context.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity); } + private Looper getLooper(@Nullable Looper looper) { + if (looper != null) { + return looper; + } + return checkNotNull(Looper.myLooper(), + "Can't toast on a thread that has not called Looper.prepare()"); + } + /** * Show the view for the specified duration. */ public void show() { - if (mNextView == null) { - throw new RuntimeException("setView must have been called"); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + checkState(mNextView != null || mText != null, "You must either set a text or a view"); + } else { + if (mNextView == null) { + throw new RuntimeException("setView must have been called"); + } } INotificationManager service = getService(); @@ -155,10 +204,18 @@ public class Toast { final int displayId = mContext.getDisplayId(); try { - if (mIsCustomToast) { - service.enqueueToast(pkg, mToken, tn, mDuration, displayId); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + if (mNextView != null) { + // It's a custom toast + service.enqueueToast(pkg, mToken, tn, mDuration, displayId); + } else { + // It's a text toast + ITransientNotificationCallback callback = + new CallbackBinder(mCallbacks, mHandler); + service.enqueueTextToast(pkg, mToken, mText, mDuration, displayId, callback); + } } else { - service.enqueueTextToast(pkg, mToken, tn, mDuration, displayId); + service.enqueueToast(pkg, mToken, tn, mDuration, displayId); } } catch (RemoteException e) { // Empty @@ -171,7 +228,16 @@ public class Toast { * after the appropriate duration. */ public void cancel() { - mTN.cancel(); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM) + && mNextView == null) { + try { + getService().cancelToast(mContext.getOpPackageName(), mToken); + } catch (RemoteException e) { + // Empty + } + } else { + mTN.cancel(); + } } /** @@ -187,7 +253,6 @@ public class Toast { */ @Deprecated public void setView(View view) { - mIsCustomToast = true; mNextView = view; } @@ -203,7 +268,6 @@ public class Toast { * will not have custom toast views displayed. */ public View getView() { - mIsCustomToast = true; return mNextView; } @@ -298,8 +362,8 @@ public class Toast { */ public void addCallback(@NonNull Callback callback) { checkNotNull(callback); - synchronized (mTN.mCallbacks) { - mTN.mCallbacks.add(callback); + synchronized (mCallbacks) { + mCallbacks.add(callback); } } @@ -307,8 +371,8 @@ public class Toast { * Removes a callback previously added with {@link #addCallback(Callback)}. */ public void removeCallback(@NonNull Callback callback) { - synchronized (mTN.mCallbacks) { - mTN.mCallbacks.remove(callback); + synchronized (mCallbacks) { + mCallbacks.remove(callback); } } @@ -338,22 +402,30 @@ public class Toast { /** * Make a standard toast to display using the specified looper. * If looper is null, Looper.myLooper() is used. + * * @hide */ public static Toast makeText(@NonNull Context context, @Nullable Looper looper, @NonNull CharSequence text, @Duration int duration) { - Toast result = new Toast(context, looper); - - LayoutInflater inflate = (LayoutInflater) - context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); - TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message); - tv.setText(text); - - result.mNextView = v; - result.mDuration = duration; - - return result; + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + Toast result = new Toast(context, looper); + result.mText = text; + result.mDuration = duration; + return result; + } else { + Toast result = new Toast(context, looper); + + LayoutInflater inflate = (LayoutInflater) + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null); + TextView tv = (TextView) v.findViewById(com.android.internal.R.id.message); + tv.setText(text); + + result.mNextView = v; + result.mDuration = duration; + + return result; + } } /** @@ -385,14 +457,23 @@ public class Toast { * @param s The new text for the Toast. */ public void setText(CharSequence s) { - if (mNextView == null) { - throw new RuntimeException("This Toast was not created with Toast.makeText()"); - } - TextView tv = mNextView.findViewById(com.android.internal.R.id.message); - if (tv == null) { - throw new RuntimeException("This Toast was not created with Toast.makeText()"); + if (Compatibility.isChangeEnabled(CHANGE_TEXT_TOASTS_IN_THE_SYSTEM)) { + if (mNextView != null) { + throw new IllegalStateException( + "Text provided for custom toast, remove previous setView() calls if you " + + "want a text toast instead."); + } + mText = s; + } else { + if (mNextView == null) { + throw new RuntimeException("This Toast was not created with Toast.makeText()"); + } + TextView tv = mNextView.findViewById(com.android.internal.R.id.message); + if (tv == null) { + throw new RuntimeException("This Toast was not created with Toast.makeText()"); + } + tv.setText(s); } - tv.setText(s); } // ======================================================================================= @@ -442,12 +523,18 @@ public class Toast { final Binder mToken; @GuardedBy("mCallbacks") - private final List<Callback> mCallbacks = new ArrayList<>(); + private final List<Callback> mCallbacks; static final long SHORT_DURATION_TIMEOUT = 4000; static final long LONG_DURATION_TIMEOUT = 7000; - TN(String packageName, Binder token, @Nullable Looper looper) { + /** + * Creates a {@link ITransientNotification} object. + * + * The parameter {@code callbacks} is not copied and is accessed with itself as its own + * lock. + */ + TN(String packageName, Binder token, List<Callback> callbacks, @Nullable Looper looper) { // XXX This should be changed to use a Dialog, with a Theme.Toast // defined that sets up the layout params appropriately. final WindowManager.LayoutParams params = mParams; @@ -464,15 +551,8 @@ public class Toast { mPackageName = packageName; mToken = token; + mCallbacks = callbacks; - if (looper == null) { - // Use Looper.myLooper() if looper is not specified. - looper = Looper.myLooper(); - if (looper == null) { - throw new RuntimeException( - "Can't toast on a thread that has not called Looper.prepare()"); - } - } mHandler = new Handler(looper, null) { @Override public void handleMessage(Message msg) { @@ -655,4 +735,46 @@ public class Toast { */ public void onToastHidden() {} } + + private static class CallbackBinder extends ITransientNotificationCallback.Stub { + private final Handler mHandler; + + @GuardedBy("mCallbacks") + private final List<Callback> mCallbacks; + + /** + * Creates a {@link ITransientNotificationCallback} object. + * + * The parameter {@code callbacks} is not copied and is accessed with itself as its own + * lock. + */ + private CallbackBinder(List<Callback> callbacks, Handler handler) { + mCallbacks = callbacks; + mHandler = handler; + } + + @Override + public void onToastShown() { + mHandler.post(() -> { + for (Callback callback : getCallbacks()) { + callback.onToastShown(); + } + }); + } + + @Override + public void onToastHidden() { + mHandler.post(() -> { + for (Callback callback : getCallbacks()) { + callback.onToastHidden(); + } + }); + } + + private List<Callback> getCallbacks() { + synchronized (mCallbacks) { + return new ArrayList<>(mCallbacks); + } + } + } } diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index de64573d1e24..b232efc8f46c 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -364,6 +364,12 @@ public final class SystemUiDeviceConfigFlags { */ public static final String NAV_BAR_HANDLE_FORCE_OPAQUE = "nav_bar_handle_force_opaque"; + /** + * (boolean) Whether to force the Nav Bar handle to remain visible over the lockscreen. + */ + public static final String NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN = + "nav_bar_handle_show_over_lockscreen"; + private SystemUiDeviceConfigFlags() { } } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index aa0ac37b007a..a2736333383e 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -16,6 +16,7 @@ package com.android.internal.statusbar; +import android.app.ITransientNotificationCallback; import android.content.ComponentName; import android.graphics.Rect; import android.hardware.biometrics.IBiometricServiceReceiverInternal; @@ -198,4 +199,15 @@ oneway interface IStatusBar * Dismiss the warning that the device is about to go to sleep due to user inactivity. */ void dismissInattentiveSleepWarning(boolean animated); + + /** + * Displays a text toast. + */ + void showToast(String packageName, IBinder token, CharSequence text, IBinder windowToken, + int duration, @nullable ITransientNotificationCallback callback); + + /** + * Cancels toast with token {@code token} in {@code packageName}. + */ + void hideToast(String packageName, IBinder token); } diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index eb7d432b559b..30e914de45c2 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -34,7 +34,6 @@ #include <string> #define DEBUG_PARCEL 0 -#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10)) static jclass gBitmap_class; static jfieldID gBitmap_nativePtr; @@ -587,7 +586,6 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { android::Parcel* p = android::parcelForJavaObject(env, parcel); - const bool isMutable = p->readInt32() != 0; const SkColorType colorType = (SkColorType)p->readInt32(); const SkAlphaType alphaType = (SkAlphaType)p->readInt32(); const uint32_t colorSpaceSize = p->readUint32(); @@ -636,11 +634,10 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the bitmap in place from the ashmem region if possible otherwise copy. sk_sp<Bitmap> nativeBitmap; - if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) { + if (blob.fd() >= 0 && !blob.isMutable()) { #if DEBUG_PARCEL - ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob " + ALOGD("Bitmap.createFromParcel: mapped contents of bitmap from %s blob " "(fds %s)", - isMutable ? "mutable" : "immutable", blob.isMutable() ? "mutable" : "immutable", p->allowFds() ? "allowed" : "forbidden"); #endif @@ -657,7 +654,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { // Map the pixels in place and take ownership of the ashmem region. We must also respect the // rowBytes value already set on the bitmap instead of attempting to compute our own. nativeBitmap = Bitmap::createFrom(bitmap->info(), bitmap->rowBytes(), dupFd, - const_cast<void*>(blob.data()), size, !isMutable); + const_cast<void*>(blob.data()), size, true); if (!nativeBitmap) { close(dupFd); blob.release(); @@ -695,7 +692,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } return createBitmap(env, nativeBitmap.release(), - getPremulBitmapCreateFlags(isMutable), NULL, NULL, density); + getPremulBitmapCreateFlags(false), NULL, NULL, density); #else doThrowRE(env, "Cannot use parcels outside of Android"); return NULL; @@ -703,9 +700,7 @@ static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) { } static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, - jlong bitmapHandle, - jboolean isMutable, jint density, - jobject parcel) { + jlong bitmapHandle, jint density, jobject parcel) { #ifdef __ANDROID__ // Layoutlib does not support parcel if (parcel == NULL) { SkDebugf("------- writeToParcel null parcel\n"); @@ -718,7 +713,6 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, auto bitmapWrapper = reinterpret_cast<BitmapWrapper*>(bitmapHandle); bitmapWrapper->getSkBitmap(&bitmap); - p->writeInt32(isMutable); p->writeInt32(bitmap.colorType()); p->writeInt32(bitmap.alphaType()); SkColorSpace* colorSpace = bitmap.colorSpace(); @@ -745,7 +739,7 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, // Transfer the underlying ashmem region if we have one and it's immutable. android::status_t status; int fd = bitmapWrapper->bitmap().getAshmemFd(); - if (fd >= 0 && !isMutable && p->allowFds()) { + if (fd >= 0 && p->allowFds()) { #if DEBUG_PARCEL ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as " "immutable blob (fds %s)", @@ -761,17 +755,14 @@ static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject, } // Copy the bitmap to a new blob. - bool mutableCopy = isMutable; #if DEBUG_PARCEL - ALOGD("Bitmap.writeToParcel: copying %s bitmap into new %s blob (fds %s)", - isMutable ? "mutable" : "immutable", - mutableCopy ? "mutable" : "immutable", + ALOGD("Bitmap.writeToParcel: copying bitmap into new blob (fds %s)", p->allowFds() ? "allowed" : "forbidden"); #endif size_t size = bitmap.computeByteSize(); android::Parcel::WritableBlob blob; - status = p->writeBlob(size, mutableCopy, &blob); + status = p->writeBlob(size, false, &blob); if (status) { doThrowRE(env, "Could not copy bitmap to parcel blob."); return JNI_FALSE; @@ -1109,7 +1100,7 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeCreateFromParcel", "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;", (void*)Bitmap_createFromParcel }, - { "nativeWriteToParcel", "(JZILandroid/os/Parcel;)Z", + { "nativeWriteToParcel", "(JILandroid/os/Parcel;)Z", (void*)Bitmap_writeToParcel }, { "nativeExtractAlpha", "(JJ[I)Landroid/graphics/Bitmap;", (void*)Bitmap_extractAlpha }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index fdfac973b871..020a8352ad07 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -94,7 +94,6 @@ <protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" /> <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" /> <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" /> - <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" /> <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" /> <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" /> diff --git a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java index 895b22c7037c..4370462279b2 100644 --- a/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java +++ b/core/tests/coretests/src/android/hardware/display/BrightnessConfigurationTest.java @@ -132,7 +132,7 @@ public class BrightnessConfigurationTest { BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); builder.setShouldCollectColorSamples(true); - builder.setShortTermModelTimeout(1234L); + builder.setShortTermModelTimeoutMillis(1234L); builder.setShortTermModelLowerLuxMultiplier(0.9f); builder.setShortTermModelUpperLuxMultiplier(0.2f); builder.addCorrectionByCategory(3, @@ -153,7 +153,7 @@ public class BrightnessConfigurationTest { BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); builder.setShouldCollectColorSamples(true); - builder.setShortTermModelTimeout(123L); + builder.setShortTermModelTimeoutMillis(123L); builder.setShortTermModelLowerLuxMultiplier(0.4f); builder.setShortTermModelUpperLuxMultiplier(0.8f); builder.addCorrectionByCategory(3, @@ -236,7 +236,7 @@ public class BrightnessConfigurationTest { assertNotEquals(baseConfig, colorCollectionDiffers); builder = new BrightnessConfiguration.Builder(LUX_LEVELS, NITS_LEVELS); - builder.setShortTermModelTimeout(300L); + builder.setShortTermModelTimeoutMillis(300L); BrightnessConfiguration timeoutDiffers = builder.build(); assertNotEquals(baseConfig, timeoutDiffers); diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java index 70c266a765e4..ac6385333b35 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestRunner.java @@ -58,7 +58,7 @@ public class DownloadManagerTestRunner extends InstrumentationTestRunner { } // enable verbose wifi logging ((WifiManager)getContext().getSystemService(Context.WIFI_SERVICE)) - .enableVerboseLogging(1); + .setVerboseLoggingEnabled(true); super.onCreate(icicle); } diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 1e98e3afa97c..79589bf13853 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -697,12 +697,6 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "-650040763": { - "message": "rotationForOrientation(orient=%d, last=%d); user=%d %s", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/DisplayRotation.java" - }, "-635082269": { "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b", "level": "INFO", @@ -901,6 +895,12 @@ "group": "WM_DEBUG_WINDOW_MOVEMENT", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-177040661": { + "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s", + "level": "DEBUG", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" + }, "-167822951": { "message": "Attempted to add starting window to token with already existing starting window", "level": "WARN", @@ -1105,6 +1105,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java" }, + "202263690": { + "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/DisplayRotation.java" + }, "221540118": { "message": "mUserActivityTimeout set to %d", "level": "DEBUG", diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index ac094ba5d5d2..9c2e95fab455 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -2132,7 +2132,7 @@ public final class Bitmap implements Parcelable { public void writeToParcel(Parcel p, int flags) { checkRecycled("Can't parcel a recycled bitmap"); noteHardwareBitmapSlowCall(); - if (!nativeWriteToParcel(mNativePtr, isMutable(), mDensity, p)) { + if (!nativeWriteToParcel(mNativePtr, mDensity, p)) { throw new RuntimeException("native writeToParcel failed"); } } @@ -2285,7 +2285,6 @@ public final class Bitmap implements Parcelable { private static native Bitmap nativeCreateFromParcel(Parcel p); // returns true on success private static native boolean nativeWriteToParcel(long nativeBitmap, - boolean isMutable, int density, Parcel p); // returns a new bitmap built from the native bitmap's alpha, and the paint diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index f61d55ef2a30..57405d762b76 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -52,6 +52,7 @@ import java.util.stream.Collectors; * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_WIDTH}</td><td>Integer</td><td>optional, the pixel aspect ratio width</td></tr> * <tr><td>{@link #KEY_PIXEL_ASPECT_RATIO_HEIGHT}</td><td>Integer</td><td>optional, the pixel aspect ratio height</td></tr> * <tr><td>{@link #KEY_BIT_RATE}</td><td>Integer</td><td><b>encoder-only</b>, desired bitrate in bits/second</td></tr> + * <tr><td>{@link #KEY_DURATION}</td><td>long</td><td>the duration of the content (in microseconds)</td></tr> * </table> * * Video formats have the following keys: diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp index 79bcc15e1f0f..c1143ce9c3dc 100644 --- a/native/graphics/jni/imagedecoder.cpp +++ b/native/graphics/jni/imagedecoder.cpp @@ -325,11 +325,9 @@ int AImageDecoder_decodeImage(AImageDecoder* decoder, ImageDecoder* imageDecoder = toDecoder(decoder); - const int height = imageDecoder->getOutputInfo().height(); - const size_t minStride = AImageDecoder_getMinimumStride(decoder); - // If this calculation were to overflow, it would have been caught in - // setTargetSize. - if (stride < minStride || size < stride * (height - 1) + minStride) { + SkImageInfo info = imageDecoder->getOutputInfo(); + size_t minSize = info.computeByteSize(stride); + if (SkImageInfo::ByteSizeOverflowed(minSize) || size < minSize || !info.validRowBytes(stride)) { return ANDROID_IMAGE_DECODER_BAD_PARAMETER; } diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index 981c129a0965..e2297e44fdfe 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -80,5 +80,6 @@ <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> <item>com.android.systemui.theme.ThemeOverlayController</item> <item>com.android.systemui.navigationbar.car.CarNavigationBar</item> + <item>com.android.systemui.toast.ToastUI</item> </string-array> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 9d4c24e8faa4..84dde05afb2e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1141,7 +1141,7 @@ public class AccessPoint implements Comparable<AccessPoint> { } else if (isActive()) { summary.append(getSummary(mContext, /* ssid */ null, getDetailedState(), mInfo != null && mInfo.isEphemeral(), - mInfo != null ? mInfo.getAppPackageName() : null)); + mInfo != null ? mInfo.getRequestingPackageName() : null)); } else { // not active if (mConfig != null && mConfig.hasNoInternetAccess()) { int messageID = mConfig.getNetworkSelectionStatus().isNetworkPermanentlyDisabled() diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index ed4ff085aeac..26abf715369c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -226,7 +226,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mConnectivityManager = connectivityManager; // check if verbose logging developer option has been turned on or off - sVerboseLogging = mWifiManager != null && (mWifiManager.getVerboseLoggingLevel() > 0); + sVerboseLogging = mWifiManager != null && mWifiManager.isVerboseLoggingEnabled(); mFilter = filter; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index b93b0001f5de..78ccba02fb04 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -102,10 +102,10 @@ public class WifiUtils { if (accessPoint.getSpeed() != AccessPoint.Speed.NONE) { visibility.append(" speed=").append(accessPoint.getSpeedLabel()); } - visibility.append(String.format(" tx=%.1f,", info.getTxSuccessRate())); - visibility.append(String.format("%.1f,", info.getTxRetriesRate())); - visibility.append(String.format("%.1f ", info.getTxBadRate())); - visibility.append(String.format("rx=%.1f", info.getRxSuccessRate())); + visibility.append(String.format(" tx=%.1f,", info.getSuccessfulTxPacketsPerSecond())); + visibility.append(String.format("%.1f,", info.getRetriedTxPacketsPerSecond())); + visibility.append(String.format("%.1f ", info.getLostTxPacketsPerSecond())); + visibility.append(String.format("rx=%.1f", info.getSuccessfulRxPacketsPerSecond())); } int maxRssi5 = INVALID_RSSI; diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 03201ae6d5ba..42f3cbb04cf8 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -507,7 +507,7 @@ public class AccessPointTest { WifiInfo wifiInfo = new WifiInfo(); wifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID)); wifiInfo.setEphemeral(true); - wifiInfo.setAppPackageName(appPackageName); + wifiInfo.setRequestingPackageName(appPackageName); wifiInfo.setRssi(rssi); Context context = mock(Context.class); diff --git a/packages/SystemUI/res/color/light_background.xml b/packages/SystemUI/res/color/light_background.xml new file mode 100644 index 000000000000..2effd991f666 --- /dev/null +++ b/packages/SystemUI/res/color/light_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_background" /> + <item android:color="@color/GM2_yellow_50" /> +</selector> diff --git a/packages/SystemUI/res/color/light_foreground.xml b/packages/SystemUI/res/color/light_foreground.xml new file mode 100644 index 000000000000..8143028795df --- /dev/null +++ b/packages/SystemUI/res/color/light_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_orange_900" /> +</selector> diff --git a/packages/SystemUI/res/color/lock_background.xml b/packages/SystemUI/res/color/lock_background.xml new file mode 100644 index 000000000000..646fe5dfe712 --- /dev/null +++ b/packages/SystemUI/res/color/lock_background.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_background" /> + <item android:color="@color/GM2_blue_50" /> +</selector> diff --git a/packages/SystemUI/res/color/lock_foreground.xml b/packages/SystemUI/res/color/lock_foreground.xml new file mode 100644 index 000000000000..3e05653bce92 --- /dev/null +++ b/packages/SystemUI/res/color/lock_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_blue_700" /> +</selector> diff --git a/packages/SystemUI/res/color/unknown_foreground.xml b/packages/SystemUI/res/color/unknown_foreground.xml new file mode 100644 index 000000000000..bf028f18a7de --- /dev/null +++ b/packages/SystemUI/res/color/unknown_foreground.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_enabled="false" + android:color="@color/control_default_foreground" /> + <item android:color="@color/GM2_blue_700" /> + </selector> diff --git a/packages/SystemUI/res/drawable/control_background.xml b/packages/SystemUI/res/drawable/control_background.xml new file mode 100644 index 000000000000..b246ea0a3935 --- /dev/null +++ b/packages/SystemUI/res/drawable/control_background.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright 2020, 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. +*/ +--> +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + <item> + <shape> + <solid android:color="?android:attr/colorBackgroundFloating"/> + <corners android:radius="@dimen/control_corner_radius" /> + </shape> + </item> + <item + android:id="@+id/clip_layer"> + <clip + android:clipOrientation="horizontal" + android:drawable="@drawable/control_layer"/> + </item> +</layer-list> diff --git a/packages/SystemUI/res/drawable/control_layer.xml b/packages/SystemUI/res/drawable/control_layer.xml new file mode 100644 index 000000000000..fe8c4a4af1bb --- /dev/null +++ b/packages/SystemUI/res/drawable/control_layer.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright 2020, 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. +*/ +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <solid android:color="@android:color/transparent"/> + <corners android:radius="@dimen/control_corner_radius" /> +</shape> diff --git a/packages/SystemUI/res/drawable/control_no_favorites_background.xml b/packages/SystemUI/res/drawable/control_no_favorites_background.xml new file mode 100644 index 000000000000..1e282ad0eec7 --- /dev/null +++ b/packages/SystemUI/res/drawable/control_no_favorites_background.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright 2020, 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. +*/ +--> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <stroke android:width="1dp" android:color="?android:attr/colorBackgroundFloating"/> + <corners android:radius="@dimen/control_corner_radius" /> +</shape> diff --git a/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml new file mode 100644 index 000000000000..45a658fe07da --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_device_thermostat_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,9h-5v2h5m3,-6h-8v2h8m-9,11.97c0.62,-0.83 1,-1.85 1,-2.97 0,-1.63 -0.79,-3.09 -2,-4V6c0,-1.66 -1.34,-3 -3,-3S5,4.34 5,6v6c-1.21,0.91 -2,2.37 -2,4 0,1.12 0.38,2.14 1,2.97V19h0.02c0.91,1.21 2.35,2 3.98,2s3.06,-0.79 3.98,-2H12v-0.03zM6.2,13.6L7,13V6c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v7l0.8,0.6c0.75,0.57 1.2,1.46 1.2,2.4H5c0,-0.94 0.45,-1.84 1.2,-2.4z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml new file mode 100644 index 000000000000..78c3cc54f022 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_light_off_gm2_24px.xml @@ -0,0 +1,19 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M9,21v-1h6v1c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1z"/> + <group> + <clip-path android:pathData="M0,0h24v24H0z M 0,0"/> + </group> + <path + android:fillColor="#FF000000" + android:pathData="M12,2c-1.89,0 -3.6,0.75 -4.86,1.97l1.41,1.41C9.45,4.53 10.67,4 12,4c2.76,0 5,2.24 5,5 0,1.28 -0.5,2.5 -1.36,3.42l-0.02,0.02 1.41,1.41C18.25,12.6 19,10.89 19,9c0,-3.86 -3.14,-7 -7,-7z" + android:fillType="evenOdd"/> + <path + android:fillColor="#FF000000" + android:pathData="M2.92,2.29L1.65,3.57l3.59,3.59C5.09,7.75 5,8.36 5,9c0,2.38 1.19,4.47 3,5.74V17c0,0.55 0.45,1 1,1h6c0.3,0 0.57,-0.13 0.75,-0.34L20.09,22l1.27,-1.27L2.92,2.29zM10,16v-2.3l-0.85,-0.6C7.8,12.16 7,10.63 7,9v-0.08L14.09,16H10z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml new file mode 100644 index 000000000000..f4299e6cda11 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_lock_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml new file mode 100644 index 000000000000..59fe0a914656 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_lock_open_gm2_24px.xml @@ -0,0 +1,12 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h2c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/> + <path + android:fillColor="#FF000000" + android:pathData="M12,15m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_more_vert.xml b/packages/SystemUI/res/drawable/ic_more_vert.xml new file mode 100644 index 000000000000..1309fa875b55 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_more_vert.xml @@ -0,0 +1,24 @@ +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml new file mode 100644 index 000000000000..cd957196e4dc --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_power_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M16,9v4.66l-3.5,3.51V19h-1v-1.83L8,13.65V9h8m0,-6h-2v4h-4V3H8v4h-0.01C6.9,6.99 6,7.89 6,8.98v5.52L9.5,18v3h5v-3l3.5,-3.51V9c0,-1.1 -0.9,-2 -2,-2V3z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml new file mode 100644 index 000000000000..3eb7dd637abe --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_power_off_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M21.19,21.19L2.81,2.81 1.39,4.22l4.63,4.63L6,14.5 9.5,18v3h5v-3l0.34,-0.34 4.94,4.94 1.41,-1.41zM12.5,17.17L12.5,19h-1v-1.83L8,13.65v-2.83l5.42,5.42 -0.92,0.93zM11.83,9L8,5.17L8,3h2v4h4L14,3h2v4c1.1,0 2,0.9 2,2v5.49l-0.34,0.34L16,13.17L16,9h-4.17z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml new file mode 100644 index 000000000000..f4edd875ddff --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_power_settings_new_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M11,2h2v10h-2zM18.37,5.64l-1.41,1.41c2.73,2.73 2.72,7.16 -0.01,9.89 -2.73,2.73 -7.17,2.73 -9.89,0.01 -2.73,-2.73 -2.74,-7.18 -0.01,-9.91l-1.41,-1.4c-3.51,3.51 -3.51,9.21 0.01,12.73 3.51,3.51 9.21,3.51 12.72,-0.01 3.51,-3.51 3.51,-9.2 0,-12.72z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml new file mode 100644 index 000000000000..bb535ceaed8c --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_switches_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M19,9h-8.02C10.06,7.79 8.63,7 7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5c1.63,0 3.06,-0.79 3.98,-2H19c1.66,0 3,-1.34 3,-3S20.66,9 19,9zM19,13h-7.1c0.07,-0.32 0.1,-0.66 0.1,-1s-0.04,-0.68 -0.1,-1H19c0.55,0 1,0.45 1,1S19.55,13 19,13z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml new file mode 100644 index 000000000000..86b9591238f1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_vacuum_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M4,16c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3zM4,20c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM23,20v2h-7v-2h2.49L12.01,4.59C11.6,3.63 10.66,3 9.61,3 8.17,3 7,4.17 7,5.61L7,9h2c2.21,0 4,1.79 4,4v9L7.99,22c0.44,-0.58 0.76,-1.26 0.91,-2L11,20v-7c0,-1.1 -0.9,-2 -2,-2L4,11v3c-0.71,0 -1.39,0.15 -2,0.42L2,9h3L5,5.61C5,3.07 7.07,1 9.61,1c1.86,0 3.53,1.11 4.25,2.82L20.66,20L23,20z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml b/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml new file mode 100644 index 000000000000..687c9c417fa6 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_videocam_gm2_24px.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M18,10.48L18,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-4.48l4,3.98v-11l-4,3.98zM16,9.69L16,18L4,18L4,6h12v3.69z"/> +</vector> diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml new file mode 100644 index 000000000000..3c4c61e30bc1 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<androidx.constraintlayout.widget.ConstraintLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="@dimen/control_height" + android:padding="@dimen/control_padding" + android:clickable="true" + android:focusable="true" + android:layout_marginLeft="3dp" + android:layout_marginRight="3dp" + android:background="@drawable/control_background"> + + <ImageView + android:id="@+id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + <TextView + android:id="@+id/status" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="@dimen/control_status_normal" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:paddingLeft="3dp" + app:layout_constraintBottom_toBottomOf="@+id/icon" + app:layout_constraintStart_toEndOf="@+id/icon" /> + + <TextView + android:id="@+id/status_extra" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="@dimen/control_status_normal" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:paddingLeft="3dp" + app:layout_constraintBottom_toBottomOf="@+id/icon" + app:layout_constraintStart_toEndOf="@+id/status" /> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="18sp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" + app:layout_constraintBottom_toTopOf="@+id/subtitle" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/icon" /> + + <TextView + android:id="@+id/subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textSize="16sp" + android:textColor="?android:attr/textColorSecondary" + android:fontFamily="@*android:string/config_headlineFontFamily" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" /> +</androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/controls_no_favorites.xml b/packages/SystemUI/res/layout/controls_no_favorites.xml new file mode 100644 index 000000000000..79672caed61b --- /dev/null +++ b/packages/SystemUI/res/layout/controls_no_favorites.xml @@ -0,0 +1,18 @@ +<merge + xmlns:android="http://schemas.android.com/apk/res/android"> + <TextView + android:id="@+id/controls_title" + android:text="@string/quick_controls_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:gravity="center" + android:textSize="25dp" + android:paddingTop="40dp" + android:paddingBottom="40dp" + android:layout_marginLeft="10dp" + android:layout_marginRight="10dp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" + android:background="@drawable/control_no_favorites_background"/> +</merge> diff --git a/packages/SystemUI/res/layout/controls_row.xml b/packages/SystemUI/res/layout/controls_row.xml new file mode 100644 index 000000000000..13a6b36accd3 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_row.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/control_spacing" /> diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml new file mode 100644 index 000000000000..7804fe6b6272 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_with_favorites.xml @@ -0,0 +1,35 @@ +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <androidx.constraintlayout.widget.ConstraintLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:text="@string/quick_controls_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:singleLine="true" + android:gravity="center" + android:textSize="25dp" + android:textColor="?android:attr/textColorPrimary" + android:fontFamily="@*android:string/config_headlineFontFamily" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent"/> + <ImageView + android:id="@+id/controls_more" + android:src="@drawable/ic_more_vert" + android:layout_width="34dp" + android:layout_height="24dp" + android:layout_marginEnd="10dp" + app:layout_constraintEnd_toEndOf="parent"/> + + </androidx.constraintlayout.widget.ConstraintLayout> + + <LinearLayout + android:id="@+id/global_actions_controls_list" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" /> +</merge> diff --git a/packages/SystemUI/res/layout/global_actions_grid_v2.xml b/packages/SystemUI/res/layout/global_actions_grid_v2.xml index 4cfb47e3c642..674148495478 100644 --- a/packages/SystemUI/res/layout/global_actions_grid_v2.xml +++ b/packages/SystemUI/res/layout/global_actions_grid_v2.xml @@ -111,20 +111,7 @@ app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@id/global_actions_panel"> - <TextView - android:text="Home" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:singleLine="true" - android:gravity="center" - android:textSize="25dp" - android:textColor="?android:attr/textColorPrimary" - android:fontFamily="@*android:string/config_headlineFontFamily" /> - <LinearLayout - android:id="@+id/global_actions_controls_list" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" /> + </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> </ScrollView> diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml index 4cc5a6731108..dd4c3210922a 100644 --- a/packages/SystemUI/res/values-television/config.xml +++ b/packages/SystemUI/res/values-television/config.xml @@ -36,5 +36,6 @@ <item>com.android.systemui.SliceBroadcastRelayHandler</item> <item>com.android.systemui.SizeCompatModeActivityController</item> <item>com.android.systemui.statusbar.notification.InstantAppNotifier</item> + <item>com.android.systemui.toast.ToastUI</item> </string-array> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 8dd2a8b9d07a..09058f2460cb 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -200,18 +200,28 @@ <color name="GM2_grey_800">#3C4043</color> <color name="GM2_grey_900">#202124</color> + <color name="GM2_red_50">#FCE8E6</color> <color name="GM2_red_300">#F28B82</color> <color name="GM2_red_500">#B71C1C</color> <color name="GM2_red_700">#C5221F</color> + <color name="GM2_blue_50">#E8F0FE</color> <color name="GM2_blue_200">#AECBFA</color> <color name="GM2_blue_300">#8AB4F8</color> + <color name="GM2_blue_500">#FF4285F4</color> <color name="GM2_blue_600">#1A73E8</color> <color name="GM2_blue_700">#1967D2</color> + <color name="GM2_yellow_50">#FEF7E0</color> <color name="GM2_yellow_500">#FFFBBC04</color> + <color name="GM2_green_500">#FF34A853</color> - <color name="GM2_blue_500">#FF4285F4</color> + + <color name="GM2_orange_900">#B06000</color> <color name="magnification_border_color">#FF9900</color> + + <!-- controls --> + <color name="control_default_foreground">?android:attr/textColorPrimary</color> + <color name="control_default_background">?android:attr/colorBackgroundFloating</color> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index edcd8012c82c..2aa6d9512898 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -297,6 +297,7 @@ <item>com.android.systemui.theme.ThemeOverlayController</item> <item>com.android.systemui.accessibility.WindowMagnification</item> <item>com.android.systemui.accessibility.SystemActions</item> + <item>com.android.systemui.toast.ToastUI</item> </string-array> <!-- SystemUI vender service, used in config_systemUIServiceComponents. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index b40c5c0b0264..cc58b2014496 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1181,5 +1181,12 @@ <dimen name="magnifier_up_down_controls_width">45dp</dimen> <dimen name="magnifier_up_down_controls_height">40dp</dimen> + <!-- Home Controls --> + <dimen name="control_spacing">5dp</dimen> + <dimen name="control_corner_radius">15dp</dimen> + <dimen name="control_height">100dp</dimen> + <dimen name="control_padding">15dp</dimen> + <dimen name="control_status_normal">12dp</dimen> + <dimen name="control_status_expanded">18dp</dimen> <dimen name="app_icon_size">32dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 44a7fda6bce3..1f13f8dc02fe 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2546,4 +2546,7 @@ <string name="magnification_window_title">Magnification Window</string> <!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] --> <string name="magnification_controls_title">Magnification Window Controls</string> + + <!-- Quick Controls strings [CHAR LIMIT=30] --> + <string name="quick_controls_title">Quick Controls</string> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt new file mode 100644 index 000000000000..81b5f3698567 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2020 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.controls.ui + +import android.content.Context +import android.graphics.drawable.ClipDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.graphics.drawable.Icon +import android.graphics.drawable.LayerDrawable +import android.service.controls.Control +import android.service.controls.DeviceTypes +import android.service.controls.actions.BooleanAction +import android.service.controls.actions.ControlAction +import android.service.controls.actions.FloatAction +import android.service.controls.templates.ControlTemplate +import android.service.controls.templates.RangeTemplate +import android.service.controls.templates.ToggleRangeTemplate +import android.service.controls.templates.ToggleTemplate +import android.util.TypedValue +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView + +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.R + +private const val MIN_LEVEL = 0 +private const val MAX_LEVEL = 10000 + +class ControlViewHolder( + val layout: ViewGroup, + val controlsController: ControlsController +) { + val icon: ImageView = layout.requireViewById(R.id.icon) + val status: TextView = layout.requireViewById(R.id.status) + val statusExtra: TextView = layout.requireViewById(R.id.status_extra) + val title: TextView = layout.requireViewById(R.id.title) + val subtitle: TextView = layout.requireViewById(R.id.subtitle) + val context: Context = layout.getContext() + val clipLayer: ClipDrawable + val gd: GradientDrawable + lateinit var cws: ControlWithState + + init { + val ld = layout.getBackground() as LayerDrawable + ld.mutate() + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) as ClipDrawable + gd = clipLayer.getDrawable() as GradientDrawable + } + + fun bindData(cws: ControlWithState) { + this.cws = cws + + val (status, template) = cws.control?.let { + title.setText(it.getTitle()) + subtitle.setText(it.getSubtitle()) + Pair(it.getStatus(), it.getControlTemplate()) + } ?: run { + title.setText(cws.ci.controlTitle) + subtitle.setText("") + Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE) + } + + findBehavior(status, template).apply(this, cws) + } + + fun action(action: ControlAction) { + controlsController.action(cws.ci, action) + } + + private fun findBehavior(status: Int, template: ControlTemplate): Behavior { + return when { + status == Control.STATUS_UNKNOWN -> UnknownBehavior() + template is ToggleTemplate -> ToggleTemplateBehavior() + template is ToggleRangeTemplate -> ToggleRangeTemplateBehavior() + else -> { + object : Behavior { + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + cvh.status.setText(cws.control?.getStatusText()) + cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false)) + } + } + } + } + } + + internal fun applyRenderInfo(ri: RenderInfo) { + val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme()) + val bg = context.getResources().getColorStateList(ri.background, context.getTheme()) + status.setTextColor(fg) + statusExtra.setTextColor(fg) + + icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId)) + icon.setImageTintList(fg) + + gd.setColor(bg) + } + + fun setEnabled(enabled: Boolean) { + status.setEnabled(enabled) + icon.setEnabled(enabled) + } +} + +private interface Behavior { + fun apply(cvh: ControlViewHolder, cws: ControlWithState) + + fun findRenderInfo(deviceType: Int, isActive: Boolean): RenderInfo = + deviceRenderMap.getOrDefault(deviceType, unknownDeviceMap).getValue(isActive) +} + +private class UnknownBehavior : Behavior { + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + cvh.status.setText("Loading...") + cvh.applyRenderInfo(findRenderInfo(cws.ci.deviceType, false)) + } +} + +private class ToggleRangeTemplateBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var template: ToggleRangeTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var rangeTemplate: RangeTemplate + lateinit var statusExtra: TextView + lateinit var status: TextView + lateinit var context: Context + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + + statusExtra = cvh.statusExtra + status = cvh.status + + status.setText(control.getStatusText()) + + context = status.getContext() + + cvh.layout.setOnTouchListener(ToggleRangeTouchListener()) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as ToggleRangeTemplate + rangeTemplate = template.getRange() + + val checked = template.isChecked() + val deviceType = control.getDeviceType() + + updateRange((rangeTemplate.getCurrentValue() / 100.0f), checked) + + cvh.setEnabled(checked) + cvh.applyRenderInfo(findRenderInfo(deviceType, checked)) + } + + fun toggle() { + cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) + + val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL + clipLayer.setLevel(nextLevel) + } + + fun beginUpdateRange() { + status.setVisibility(View.GONE) + statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + .getDimensionPixelSize(R.dimen.control_status_expanded).toFloat()) + } + + fun updateRange(f: Float, checked: Boolean) { + clipLayer.setLevel(if (checked) (MAX_LEVEL * f).toInt() else MIN_LEVEL) + + if (checked && f < 100.0f && f > 0.0f) { + statusExtra.setText("" + (f * 100.0).toInt() + "%") + statusExtra.setVisibility(View.VISIBLE) + } else { + statusExtra.setText("") + statusExtra.setVisibility(View.GONE) + } + } + + fun endUpdateRange(f: Float) { + statusExtra.setText(" - " + (f * 100.0).toInt() + "%") + + val newValue = rangeTemplate.getMinValue() + + (f * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())) + + statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources() + .getDimensionPixelSize(R.dimen.control_status_normal).toFloat()) + status.setVisibility(View.VISIBLE) + + cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(newValue))) + } + + fun findNearestStep(value: Float): Float { + var minDiff = 1000f + + var f = rangeTemplate.getMinValue() + while (f <= rangeTemplate.getMaxValue()) { + val currentDiff = Math.abs(value - f) + if (currentDiff < minDiff) { + minDiff = currentDiff + } else { + return f - rangeTemplate.getStepValue() + } + + f += rangeTemplate.getStepValue() + } + + return rangeTemplate.getMaxValue() + } + + inner class ToggleRangeTouchListener() : View.OnTouchListener { + private var initialTouchX: Float = 0.0f + private var initialTouchY: Float = 0.0f + private var isDragging: Boolean = false + private val minDragDiff = 20 + + override fun onTouch(v: View, e: MotionEvent): Boolean { + when (e.getActionMasked()) { + MotionEvent.ACTION_DOWN -> setupTouch(e) + MotionEvent.ACTION_MOVE -> detectDrag(v, e) + MotionEvent.ACTION_UP -> endTouch(v, e) + } + + return true + } + + private fun setupTouch(e: MotionEvent) { + initialTouchX = e.getX() + initialTouchY = e.getY() + } + + private fun detectDrag(v: View, e: MotionEvent) { + val xDiff = Math.abs(e.getX() - initialTouchX) + val yDiff = Math.abs(e.getY() - initialTouchY) + + if (xDiff < minDragDiff) { + isDragging = false + } else { + if (!isDragging) { + this@ToggleRangeTemplateBehavior.beginUpdateRange() + } + v.getParent().requestDisallowInterceptTouchEvent(true) + isDragging = true + if (yDiff > xDiff) { + endTouch(v, e) + } else { + val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) + this@ToggleRangeTemplateBehavior.updateRange(percent, true) + } + } + } + + private fun endTouch(v: View, e: MotionEvent) { + if (!isDragging) { + this@ToggleRangeTemplateBehavior.toggle() + } else { + val percent = Math.max(0.0f, Math.min(1.0f, e.getX() / v.getWidth())) + this@ToggleRangeTemplateBehavior.endUpdateRange(percent) + } + + initialTouchX = 0.0f + initialTouchY = 0.0f + isDragging = false + } + } +} + +private class ToggleTemplateBehavior : Behavior { + lateinit var clipLayer: Drawable + lateinit var template: ToggleTemplate + lateinit var control: Control + lateinit var cvh: ControlViewHolder + lateinit var context: Context + lateinit var status: TextView + + override fun apply(cvh: ControlViewHolder, cws: ControlWithState) { + this.control = cws.control!! + this.cvh = cvh + status = cvh.status + + status.setText(control.getStatusText()) + + cvh.layout.setOnClickListener(View.OnClickListener() { toggle() }) + + val ld = cvh.layout.getBackground() as LayerDrawable + clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) + + template = control.getControlTemplate() as ToggleTemplate + + val checked = template.isChecked() + val deviceType = control.getDeviceType() + + clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL) + cvh.setEnabled(checked) + cvh.applyRenderInfo(findRenderInfo(deviceType, checked)) + } + + fun toggle() { + cvh.action(BooleanAction(template.getTemplateId(), !template.isChecked())) + + val nextLevel = if (template.isChecked()) MIN_LEVEL else MAX_LEVEL + clipLayer.setLevel(nextLevel) + } +} + +internal data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) + +private val unknownDeviceMap = mapOf( + false to RenderInfo( + R.drawable.ic_light_off_gm2_24px, + R.color.unknown_foreground, + R.color.unknown_foreground), + true to RenderInfo( + R.drawable.ic_lightbulb_outline_gm2_24px, + R.color.unknown_foreground, + R.color.unknown_foreground) +) + +private val deviceRenderMap = mapOf<Int, Map<Boolean, RenderInfo>>( + DeviceTypes.TYPE_UNKNOWN to unknownDeviceMap, + DeviceTypes.TYPE_LIGHT to mapOf( + false to RenderInfo( + R.drawable.ic_light_off_gm2_24px, + R.color.light_foreground, + R.color.light_background), + true to RenderInfo( + R.drawable.ic_lightbulb_outline_gm2_24px, + R.color.light_foreground, + R.color.light_background) + ), + DeviceTypes.TYPE_THERMOSTAT to mapOf( + false to RenderInfo( + R.drawable.ic_device_thermostat_gm2_24px, + R.color.light_foreground, + R.color.light_background), + true to RenderInfo( + R.drawable.ic_device_thermostat_gm2_24px, + R.color.light_foreground, + R.color.light_background) + ), + DeviceTypes.TYPE_CAMERA to mapOf( + false to RenderInfo( + R.drawable.ic_videocam_gm2_24px, + R.color.light_foreground, + R.color.light_background), + true to RenderInfo( + R.drawable.ic_videocam_gm2_24px, + R.color.light_foreground, + R.color.light_background) + ), + DeviceTypes.TYPE_LOCK to mapOf( + false to RenderInfo( + R.drawable.ic_lock_open_gm2_24px, + R.color.lock_foreground, + R.color.lock_background), + true to RenderInfo( + R.drawable.ic_lock_gm2_24px, + R.color.lock_foreground, + R.color.lock_background) + ), + DeviceTypes.TYPE_SWITCH to mapOf( + false to RenderInfo( + R.drawable.ic_switches_gm2_24px, + R.color.lock_foreground, + R.color.lock_background), + true to RenderInfo( + R.drawable.ic_switches_gm2_24px, + R.color.lock_foreground, + R.color.lock_background) + ), + DeviceTypes.TYPE_OUTLET to mapOf( + false to RenderInfo( + R.drawable.ic_power_off_gm2_24px, + R.color.lock_foreground, + R.color.lock_background), + true to RenderInfo( + R.drawable.ic_power_gm2_24px, + R.color.lock_foreground, + R.color.lock_background) + ) +) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt new file mode 100644 index 000000000000..816f0b2cb1d1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 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.controls.ui + +import android.service.controls.Control + +import com.android.systemui.controls.controller.ControlInfo + +/** + * A container for: + * <ul> + * <li>ControlInfo - Basic cached info about a Control + * <li>Control - Actual Control parcelable received directly from + * the participating application + * </ul> + */ +data class ControlWithState(val ci: ControlInfo, val control: Control?) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt index 0270c2b6b1b3..b07a75d5e757 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt @@ -19,12 +19,15 @@ package com.android.systemui.controls.ui import android.content.ComponentName import android.service.controls.Control import android.service.controls.actions.ControlAction +import android.view.ViewGroup interface ControlsUiController { + fun show(parent: ViewGroup) + fun hide() fun onRefreshState(componentName: ComponentName, controls: List<Control>) fun onActionResponse( componentName: ComponentName, controlId: String, @ControlAction.ResponseResult response: Int ) -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index 0ace1263b49b..926fb6e75594 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -16,19 +16,204 @@ package com.android.systemui.controls.ui +import android.accounts.Account +import android.accounts.AccountManager import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder import android.service.controls.Control +import android.service.controls.TokenProvider +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView + +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.controls.controller.ControlInfo +import com.android.systemui.controls.management.ControlsProviderSelectorActivity +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.R + +import dagger.Lazy + +import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton +private const val TAG = "ControlsUi" + +// TEMP CODE for MOCK +private const val TOKEN = "https://www.googleapis.com/auth/assistant" +private const val SCOPE = "oauth2:" + TOKEN +private var tokenProviderConnection: TokenProviderConnection? = null +class TokenProviderConnection(val cc: ControlsController, val context: Context) + : ServiceConnection { + private var mTokenProvider: TokenProvider? = null + + override fun onServiceConnected(cName: ComponentName, binder: IBinder) { + Thread({ + Log.i(TAG, "TokenProviderConnection connected") + mTokenProvider = TokenProvider.Stub.asInterface(binder) + + val mLastAccountName = mTokenProvider?.getAccountName() + + if (mLastAccountName == null || mLastAccountName.isEmpty()) { + Log.e(TAG, "NO ACCOUNT IS SET. Open HomeMock app") + } else { + mTokenProvider?.setAuthToken(getAuthToken(mLastAccountName)) + cc.subscribeToFavorites() + } + }, "TokenProviderThread").start() + } + + override fun onServiceDisconnected(cName: ComponentName) { + mTokenProvider = null + } + + fun getAuthToken(accountName: String): String? { + val am = AccountManager.get(context) + val accounts = am.getAccountsByType("com.google") + if (accounts == null || accounts.size == 0) { + Log.w(TAG, "No com.google accounts found") + return null + } + + var account: Account? = null + for (a in accounts) { + if (a.name.equals(accountName)) { + account = a + break + } + } + + if (account == null) { + account = accounts[0] + } + + try { + return am.blockingGetAuthToken(account!!, SCOPE, true) + } catch (e: Throwable) { + Log.e(TAG, "Error getting auth token", e) + return null + } + } +} + @Singleton -class ControlsUiControllerImpl @Inject constructor() : ControlsUiController { +class ControlsUiControllerImpl @Inject constructor ( + val controlsController: Lazy<ControlsController>, + val context: Context, + @Main val uiExecutor: Executor +) : ControlsUiController { + + private lateinit var controlInfos: List<ControlInfo> + private val controlsById = mutableMapOf<Pair<ComponentName, String>, ControlWithState>() + private val controlViewsById = mutableMapOf<String, ControlViewHolder>() + private lateinit var parent: ViewGroup + + override fun show(parent: ViewGroup) { + Log.d(TAG, "show()") + + this.parent = parent + + controlInfos = controlsController.get().getFavoriteControls() + + controlInfos.map { + ControlWithState(it, null) + }.associateByTo(controlsById) { Pair(it.ci.component, it.ci.controlId) } + + if (controlInfos.isEmpty()) { + showInitialSetupView() + } else { + showControlsView() + } + + // Temp code to pass auth + tokenProviderConnection = TokenProviderConnection(controlsController.get(), context) + val serviceIntent = Intent() + serviceIntent.setComponent(ComponentName("com.android.systemui.home.mock", + "com.android.systemui.home.mock.AuthService")) + context.bindService(serviceIntent, tokenProviderConnection!!, Context.BIND_AUTO_CREATE) + } + + private fun showInitialSetupView() { + val inflater = LayoutInflater.from(context) + inflater.inflate(R.layout.controls_no_favorites, parent, true) + + val textView = parent.requireViewById(R.id.controls_title) as TextView + textView.setOnClickListener { + val i = Intent() + i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + context.startActivity(i) + } + } + + private fun showControlsView() { + val inflater = LayoutInflater.from(context) + inflater.inflate(R.layout.controls_with_favorites, parent, true) + + val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup + var lastRow: ViewGroup = createRow(inflater, listView) + controlInfos.forEach { + Log.d(TAG, "favorited control id: " + it.controlId) + if (lastRow.getChildCount() == 2) { + lastRow = createRow(inflater, listView) + } + val item = inflater.inflate( + R.layout.controls_base_item, lastRow, false) as ViewGroup + lastRow.addView(item) + val cvh = ControlViewHolder(item, controlsController.get()) + cvh.bindData(controlsById.get(Pair(it.component, it.controlId))!!) + controlViewsById.put(it.controlId, cvh) + } + + val moreImageView = parent.requireViewById(R.id.controls_more) as View + moreImageView.setOnClickListener { + val i = Intent() + i.setComponent(ComponentName(context, ControlsProviderSelectorActivity::class.java)) + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + context.startActivity(i) + } + } + + override fun hide() { + Log.d(TAG, "hide()") + controlsController.get().unsubscribe() + context.unbindService(tokenProviderConnection) + tokenProviderConnection = null + + parent.removeAllViews() + controlsById.clear() + controlViewsById.clear() + } override fun onRefreshState(componentName: ComponentName, controls: List<Control>) { - TODO("not implemented") + Log.d(TAG, "onRefreshState()") + controls.forEach { c -> + controlsById.get(Pair(componentName, c.getControlId()))?.let { + Log.d(TAG, "onRefreshState() for id: " + c.getControlId()) + val cws = ControlWithState(it.ci, c) + controlsById.put(Pair(componentName, c.getControlId()), cws) + + uiExecutor.execute { + controlViewsById.get(c.getControlId())?.bindData(cws) + } + } + } } override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) { + Log.d(TAG, "onActionResponse()") TODO("not implemented") } -}
\ No newline at end of file + + private fun createRow(inflater: LayoutInflater, parent: ViewGroup): ViewGroup { + val row = inflater.inflate(R.layout.controls_row, parent, false) as ViewGroup + parent.addView(row) + return row + } +} diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java index d4e47f699345..5de88e17d320 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java @@ -37,6 +37,7 @@ import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarModule; import com.android.systemui.statusbar.tv.TvStatusBar; import com.android.systemui.theme.ThemeOverlayController; +import com.android.systemui.toast.ToastUI; import com.android.systemui.util.leak.GarbageMonitor; import com.android.systemui.volume.VolumeUI; @@ -153,6 +154,12 @@ public abstract class SystemUIBinder { @ClassKey(ThemeOverlayController.class) public abstract SystemUI bindThemeOverlayController(ThemeOverlayController sysui); + /** Inject into ToastUI. */ + @Binds + @IntoMap + @ClassKey(ToastUI.class) + public abstract SystemUI bindToastUI(ToastUI service); + /** Inject into TvStatusBar. */ @Binds @IntoMap diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 83f6d45465b3..80d776a59235 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -93,12 +93,13 @@ import com.android.systemui.MultiListLayout; import com.android.systemui.MultiListLayout.MultiListAdapter; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; +import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; -import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.BlurUtils; +import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -183,6 +184,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final IStatusBarService mStatusBarService; private final NotificationShadeWindowController mNotificationShadeWindowController; private GlobalActionsPanelPlugin mPanelPlugin; + private ControlsUiController mControlsUiController; /** * @param context everything needs a context :( @@ -200,7 +202,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, TelecomManager telecomManager, MetricsLogger metricsLogger, BlurUtils blurUtils, SysuiColorExtractor colorExtractor, IStatusBarService statusBarService, - NotificationShadeWindowController notificationShadeWindowController) { + NotificationShadeWindowController notificationShadeWindowController, + ControlsUiController controlsUiController) { mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; @@ -220,6 +223,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mSysuiColorExtractor = colorExtractor; mStatusBarService = statusBarService; mNotificationShadeWindowController = notificationShadeWindowController; + mControlsUiController = controlsUiController; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -455,9 +459,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mKeyguardManager.isDeviceLocked()) : null; + boolean showControls = !mKeyguardManager.isDeviceLocked() && isControlsEnabled(mContext); + ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController, mBlurUtils, mSysuiColorExtractor, mStatusBarService, - mNotificationShadeWindowController, isControlsEnabled(mContext)); + mNotificationShadeWindowController, + showControls ? mControlsUiController : null); dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. dialog.setKeyguardShowing(mKeyguardShowing); @@ -1543,13 +1550,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean mHadTopUi; private final NotificationShadeWindowController mNotificationShadeWindowController; private final BlurUtils mBlurUtils; - private final boolean mControlsEnabled; + + private ControlsUiController mControlsUiController; + private ViewGroup mControlsView; ActionsDialog(Context context, MyAdapter adapter, GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils, SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService, NotificationShadeWindowController notificationShadeWindowController, - boolean controlsEnabled) { + ControlsUiController controlsUiController) { super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions); mContext = context; mAdapter = adapter; @@ -1557,7 +1566,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mColorExtractor = sysuiColorExtractor; mStatusBarService = statusBarService; mNotificationShadeWindowController = notificationShadeWindowController; - mControlsEnabled = controlsEnabled; + mControlsUiController = controlsUiController; // Window initialization Window window = getWindow(); @@ -1639,6 +1648,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private void initializeLayout() { setContentView(getGlobalActionsLayoutId(mContext)); fixNavBarClipping(); + mControlsView = findViewById(com.android.systemui.R.id.global_actions_controls); mGlobalActionsLayout = findViewById(com.android.systemui.R.id.global_actions_view); mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); ((View) mGlobalActionsLayout.getParent()).setOnClickListener(view -> dismiss()); @@ -1674,7 +1684,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } private int getGlobalActionsLayoutId(Context context) { - if (mControlsEnabled) { + if (mControlsUiController != null) { return com.android.systemui.R.layout.global_actions_grid_v2; } @@ -1758,6 +1768,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mBlurUtils.radiusForRatio(animatedValue)); }) .start(); + if (mControlsUiController != null) { + mControlsUiController.show(mControlsView); + } } @Override @@ -1766,6 +1779,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, return; } mShowing = false; + if (mControlsUiController != null) mControlsUiController.hide(); mGlobalActionsLayout.setTranslationX(0); mGlobalActionsLayout.setTranslationY(0); mGlobalActionsLayout.setAlpha(1); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 2fc7a9cf2434..14eec59211bd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -18,6 +18,7 @@ package com.android.systemui.keyguard; import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT; +import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; @@ -53,6 +54,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; +import android.provider.DeviceConfig; import android.provider.Settings; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -371,6 +373,7 @@ public class KeyguardViewMediator extends SystemUI { private boolean mPulsing; private boolean mLockLater; + private boolean mShowHomeOverLockscreen; private boolean mWakeAndUnlocking; private IKeyguardDrawnCallback mDrawnCallback; @@ -703,6 +706,20 @@ public class KeyguardViewMediator extends SystemUI { mStatusBarKeyguardViewManagerLazy = statusBarKeyguardViewManagerLazy; mDismissCallbackRegistry = dismissCallbackRegistry; mUiBgExecutor = uiBgExecutor; + mShowHomeOverLockscreen = DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_SYSTEMUI, + NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, + /* defaultValue = */ true); + DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (properties.getKeyset().contains(NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN)) { + mShowHomeOverLockscreen = properties.getBoolean( + NAV_BAR_HANDLE_SHOW_OVER_LOCKSCREEN, true /* defaultValue */); + } + } + }); } public void userActivity() { @@ -1972,7 +1989,10 @@ public class KeyguardViewMediator extends SystemUI { // windows that appear on top, ever int flags = StatusBarManager.DISABLE_NONE; if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) { - flags |= StatusBarManager.DISABLE_HOME | StatusBarManager.DISABLE_RECENT; + if (!mShowHomeOverLockscreen) { + flags |= StatusBarManager.DISABLE_HOME; + } + flags |= StatusBarManager.DISABLE_RECENT; } if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 7c0f4f942bce..3af3701dff97 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -25,6 +25,8 @@ import static android.view.Display.INVALID_DISPLAY; import static com.android.systemui.statusbar.phone.StatusBar.ONLY_CORE_APPS; +import android.annotation.Nullable; +import android.app.ITransientNotificationCallback; import android.app.StatusBarManager; import android.app.StatusBarManager.Disable2Flags; import android.app.StatusBarManager.DisableFlags; @@ -119,6 +121,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< private static final int MSG_TOP_APP_WINDOW_CHANGED = 50 << MSG_SHIFT; private static final int MSG_SHOW_INATTENTIVE_SLEEP_WARNING = 51 << MSG_SHIFT; private static final int MSG_DISMISS_INATTENTIVE_SLEEP_WARNING = 52 << MSG_SHIFT; + private static final int MSG_SHOW_TOAST = 53 << MSG_SHIFT; + private static final int MSG_HIDE_TOAST = 54 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -308,6 +312,19 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< * due to prolonged user inactivity should be dismissed. */ default void dismissInattentiveSleepWarning(boolean animated) { } + + /** + * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int, + * ITransientNotificationCallback) + */ + default void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, + @Nullable ITransientNotificationCallback callback) { } + + /** + * @see IStatusBar#hideToast(String, IBinder) (String, IBinder) + */ + default void hideToast(String packageName, IBinder token) { } } public CommandQueue(Context context) { @@ -761,6 +778,31 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< } @Override + public void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = packageName; + args.arg2 = token; + args.arg3 = text; + args.arg4 = windowToken; + args.arg5 = callback; + args.argi1 = duration; + mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget(); + } + } + + @Override + public void hideToast(String packageName, IBinder token) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = packageName; + args.arg2 = token; + mHandler.obtainMessage(MSG_HIDE_TOAST, args).sendToTarget(); + } + } + + @Override public void onBiometricAuthenticated() { synchronized (mLock) { mHandler.obtainMessage(MSG_BIOMETRIC_AUTHENTICATED).sendToTarget(); @@ -1178,6 +1220,30 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController< mCallbacks.get(i).dismissInattentiveSleepWarning((Boolean) msg.obj); } break; + case MSG_SHOW_TOAST: { + args = (SomeArgs) msg.obj; + String packageName = (String) args.arg1; + IBinder token = (IBinder) args.arg2; + CharSequence text = (CharSequence) args.arg3; + IBinder windowToken = (IBinder) args.arg4; + ITransientNotificationCallback callback = + (ITransientNotificationCallback) args.arg5; + int duration = args.argi1; + for (Callbacks callbacks : mCallbacks) { + callbacks.showToast(packageName, token, text, windowToken, duration, + callback); + } + break; + } + case MSG_HIDE_TOAST: { + args = (SomeArgs) msg.obj; + String packageName = (String) args.arg1; + IBinder token = (IBinder) args.arg2; + for (Callbacks callbacks : mCallbacks) { + callbacks.hideToast(packageName, token); + } + break; + } } } } 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 3e3ef0ccb8ce..9e64748f2e65 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -302,14 +302,14 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mForceNavBarHandleOpaque = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, NAV_BAR_HANDLE_FORCE_OPAQUE, - /* defaultValue = */ false); + /* defaultValue = */ true); DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI, mHandler::post, new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) { mForceNavBarHandleOpaque = properties.getBoolean( - NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ false); + NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true); } } }); diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java new file mode 100644 index 000000000000..dea8c5d49dfc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2020 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.toast; + +import android.annotation.MainThread; +import android.annotation.Nullable; +import android.app.INotificationManager; +import android.app.ITransientNotificationCallback; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.WindowManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.widget.TextView; +import android.widget.Toast; + +import com.android.internal.R; +import com.android.systemui.SystemUI; +import com.android.systemui.statusbar.CommandQueue; + +import java.util.Objects; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Controls display of text toasts. + */ +@Singleton +public class ToastUI extends SystemUI implements CommandQueue.Callbacks { + private static final String TAG = "ToastUI"; + + /** + * Values taken from {@link Toast}. + */ + private static final long DURATION_SHORT = 4000; + private static final long DURATION_LONG = 7000; + + private final CommandQueue mCommandQueue; + private final WindowManager mWindowManager; + private final INotificationManager mNotificationManager; + private final AccessibilityManager mAccessibilityManager; + private ToastEntry mCurrentToast; + + @Inject + public ToastUI(Context context, CommandQueue commandQueue) { + super(context); + mCommandQueue = commandQueue; + mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mNotificationManager = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + mAccessibilityManager = AccessibilityManager.getInstance(context); + } + + @Override + public void start() { + mCommandQueue.addCallback(this); + } + + @Override + @MainThread + public void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) { + if (mCurrentToast != null) { + hideCurrentToast(); + } + View view = getView(text); + LayoutParams params = getLayoutParams(windowToken, duration); + mCurrentToast = new ToastEntry(packageName, token, view, windowToken, callback); + try { + mWindowManager.addView(view, params); + } catch (WindowManager.BadTokenException e) { + Log.w(TAG, "Error while attempting to show toast from " + packageName, e); + return; + } + trySendAccessibilityEvent(view, packageName); + if (callback != null) { + try { + callback.onToastShown(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling back " + packageName + " to notify onToastShow()", e); + } + } + } + + @Override + @MainThread + public void hideToast(String packageName, IBinder token) { + if (mCurrentToast == null || !Objects.equals(mCurrentToast.packageName, packageName) + || !Objects.equals(mCurrentToast.token, token)) { + Log.w(TAG, "Attempt to hide non-current toast from package " + packageName); + return; + } + hideCurrentToast(); + } + + @MainThread + private void hideCurrentToast() { + if (mCurrentToast.view.getParent() != null) { + mWindowManager.removeViewImmediate(mCurrentToast.view); + } + String packageName = mCurrentToast.packageName; + try { + mNotificationManager.finishToken(packageName, mCurrentToast.windowToken); + } catch (RemoteException e) { + Log.w(TAG, "Error finishing toast window token from package " + packageName, e); + } + if (mCurrentToast.callback != null) { + try { + mCurrentToast.callback.onToastHidden(); + } catch (RemoteException e) { + Log.w(TAG, "Error calling back " + packageName + " to notify onToastHide()", e); + } + } + mCurrentToast = null; + } + + private void trySendAccessibilityEvent(View view, String packageName) { + if (!mAccessibilityManager.isEnabled()) { + return; + } + AccessibilityEvent event = AccessibilityEvent.obtain( + AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED); + event.setClassName(Toast.class.getName()); + event.setPackageName(packageName); + view.dispatchPopulateAccessibilityEvent(event); + mAccessibilityManager.sendAccessibilityEvent(event); + } + + private View getView(CharSequence text) { + View view = LayoutInflater.from(mContext).inflate( + R.layout.transient_notification, null); + TextView textView = view.findViewById(com.android.internal.R.id.message); + textView.setText(text); + return view; + } + + private LayoutParams getLayoutParams(IBinder windowToken, int duration) { + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + params.width = WindowManager.LayoutParams.WRAP_CONTENT; + params.format = PixelFormat.TRANSLUCENT; + params.windowAnimations = com.android.internal.R.style.Animation_Toast; + params.type = WindowManager.LayoutParams.TYPE_TOAST; + params.setTitle("Toast"); + params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + Configuration config = mContext.getResources().getConfiguration(); + int specificGravity = mContext.getResources().getInteger( + com.android.internal.R.integer.config_toastDefaultGravity); + int gravity = Gravity.getAbsoluteGravity(specificGravity, config.getLayoutDirection()); + params.gravity = gravity; + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) { + params.horizontalWeight = 1.0f; + } + if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) { + params.verticalWeight = 1.0f; + } + params.x = 0; + params.y = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset); + params.verticalMargin = 0; + params.horizontalMargin = 0; + params.packageName = mContext.getPackageName(); + params.hideTimeoutMilliseconds = + (duration == Toast.LENGTH_LONG) ? DURATION_LONG : DURATION_SHORT; + params.token = windowToken; + return params; + } + + private static class ToastEntry { + public final String packageName; + public final IBinder token; + public final View view; + public final IBinder windowToken; + + @Nullable + public final ITransientNotificationCallback callback; + + private ToastEntry(String packageName, IBinder token, View view, IBinder windowToken, + @Nullable ITransientNotificationCallback callback) { + this.packageName = packageName; + this.token = token; + this.view = view; + this.windowToken = windowToken; + this.callback = callback; + } + } +} diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 79c693040416..37ce1d57da36 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -136,6 +136,12 @@ public class TetheringManager { */ public static final int TETHERING_NCM = 4; + /** + * Ethernet tethering type. + * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback) + */ + public static final int TETHERING_ETHERNET = 5; + public static final int TETHER_ERROR_NO_ERROR = 0; public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 57cc4dd554f1..190d25098644 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -93,6 +93,8 @@ public class IpServer extends StateMachine { private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; private static final String WIFI_P2P_IFACE_ADDR = "192.168.49.1"; private static final int WIFI_P2P_IFACE_PREFIX_LENGTH = 24; + private static final String ETHERNET_IFACE_ADDR = "192.168.50.1"; + private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24; // TODO: have PanService use some visible version of this constant private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; @@ -426,6 +428,10 @@ public class IpServer extends StateMachine { } else if (mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { srvAddr = (Inet4Address) parseNumericAddress(WIFI_P2P_IFACE_ADDR); prefixLen = WIFI_P2P_IFACE_PREFIX_LENGTH; + } else if (mInterfaceType == TetheringManager.TETHERING_ETHERNET) { + // TODO: randomize address for tethering too, similarly to wifi + srvAddr = (Inet4Address) parseNumericAddress(ETHERNET_IFACE_ADDR); + prefixLen = ETHERNET_IFACE_PREFIX_LENGTH; } else { // BT configures the interface elsewhere: only start DHCP. // TODO: make all tethering types behave the same way, and delete the bluetooth diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 02ba17e4b48b..07abe1adeb52 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -30,6 +30,7 @@ import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER; import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER; import static android.net.TetheringManager.EXTRA_ERRORED_TETHER; import static android.net.TetheringManager.TETHERING_BLUETOOTH; +import static android.net.TetheringManager.TETHERING_ETHERNET; import static android.net.TetheringManager.TETHERING_INVALID; import static android.net.TetheringManager.TETHERING_NCM; import static android.net.TetheringManager.TETHERING_USB; @@ -68,6 +69,7 @@ import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; +import android.net.EthernetManager; import android.net.IIntResultListener; import android.net.INetd; import android.net.ITetheringEventCallback; @@ -112,6 +114,7 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; @@ -214,6 +217,13 @@ public class Tethering { private boolean mDataSaverEnabled = false; private String mWifiP2pTetherInterface = null; + @GuardedBy("mPublicSync") + private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest; + @GuardedBy("mPublicSync") + private String mConfiguredEthernetIface; + @GuardedBy("mPublicSync") + private EthernetCallback mEthernetCallback; + public Tethering(TetheringDependencies deps) { mLog.mark("Tethering.constructed"); mDeps = deps; @@ -464,6 +474,10 @@ public class Tethering { result = setNcmTethering(enable); sendTetherResult(listener, result); break; + case TETHERING_ETHERNET: + result = setEthernetTethering(enable); + sendTetherResult(listener, result); + break; default: Log.w(TAG, "Invalid tether type."); sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE); @@ -540,6 +554,57 @@ public class Tethering { }, BluetoothProfile.PAN); } + private int setEthernetTethering(final boolean enable) { + final EthernetManager em = (EthernetManager) mContext.getSystemService( + Context.ETHERNET_SERVICE); + synchronized (mPublicSync) { + if (enable) { + mEthernetCallback = new EthernetCallback(); + mEthernetIfaceRequest = em.requestTetheredInterface(mEthernetCallback); + } else { + if (mConfiguredEthernetIface != null) { + stopEthernetTetheringLocked(); + mEthernetIfaceRequest.release(); + } + mEthernetCallback = null; + } + } + return TETHER_ERROR_NO_ERROR; + } + + private void stopEthernetTetheringLocked() { + if (mConfiguredEthernetIface == null) return; + changeInterfaceState(mConfiguredEthernetIface, IpServer.STATE_AVAILABLE); + stopTrackingInterfaceLocked(mConfiguredEthernetIface); + mConfiguredEthernetIface = null; + } + + private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback { + @Override + public void onAvailable(String iface) { + synchronized (mPublicSync) { + if (this != mEthernetCallback) { + // Ethernet callback arrived after Ethernet tethering stopped. Ignore. + return; + } + maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET); + changeInterfaceState(iface, IpServer.STATE_TETHERED); + mConfiguredEthernetIface = iface; + } + } + + @Override + public void onUnavailable() { + synchronized (mPublicSync) { + if (this != mEthernetCallback) { + // onAvailable called after stopping Ethernet tethering. + return; + } + stopEthernetTetheringLocked(); + } + } + } + int tether(String iface) { return tether(iface, IpServer.STATE_TETHERED); } @@ -590,6 +655,7 @@ public class Tethering { stopTethering(TETHERING_WIFI_P2P); stopTethering(TETHERING_USB); stopTethering(TETHERING_BLUETOOTH); + stopTethering(TETHERING_ETHERNET); } int getLastTetherError(String iface) { diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 53782fed1c50..13174c5bb57a 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -19,6 +19,7 @@ android_test { certificate: "platform", srcs: [ "src/**/*.java", + "src/**/*.kt", ], test_suites: [ "device-tests", diff --git a/packages/Tethering/tests/unit/AndroidManifest.xml b/packages/Tethering/tests/unit/AndroidManifest.xml index 0a1cdd35b10c..530bc0788a78 100644 --- a/packages/Tethering/tests/unit/AndroidManifest.xml +++ b/packages/Tethering/tests/unit/AndroidManifest.xml @@ -16,6 +16,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.networkstack.tethering.tests.unit"> + <uses-permission android:name="android.permission.TETHER_PRIVILEGED"/> + <application android:debuggable="true"> <uses-library android:name="android.test.runner" /> </application> diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index 9245a1da43b2..0b7029b1a71d 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -109,6 +109,7 @@ import java.util.concurrent.Executors; public final class ContentCaptureManagerService extends AbstractMasterSystemService<ContentCaptureManagerService, ContentCapturePerUserService> { + private static final String TAG = ContentCaptureManagerService.class.getSimpleName(); static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions"; private static final int MAX_TEMP_SERVICE_DURATION_MS = 1_000 * 60 * 2; // 2 minutes @@ -167,11 +168,11 @@ public final class ContentCaptureManagerService extends setDeviceConfigProperties(); if (mDevCfgLogHistorySize > 0) { - if (debug) Slog.d(mTag, "log history size: " + mDevCfgLogHistorySize); + if (debug) Slog.d(TAG, "log history size: " + mDevCfgLogHistorySize); mRequestsHistory = new LocalLog(mDevCfgLogHistorySize); } else { if (debug) { - Slog.d(mTag, "disabled log history because size is " + mDevCfgLogHistorySize); + Slog.d(TAG, "disabled log history because size is " + mDevCfgLogHistorySize); } mRequestsHistory = null; } @@ -182,7 +183,7 @@ public final class ContentCaptureManagerService extends final boolean disabled = !isEnabledBySettings(userId); // Sets which services are disabled by settings if (disabled) { - Slog.i(mTag, "user " + userId + " disabled by settings"); + Slog.i(TAG, "user " + userId + " disabled by settings"); if (mDisabledBySettings == null) { mDisabledBySettings = new SparseBooleanArray(1); } @@ -245,7 +246,7 @@ public final class ContentCaptureManagerService extends @Override // from AbstractMasterSystemService protected void enforceCallingPermissionForManagement() { - getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag); + getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, TAG); } @Override // from AbstractMasterSystemService @@ -269,7 +270,7 @@ public final class ContentCaptureManagerService extends isEnabledBySettings(userId)); return; default: - Slog.w(mTag, "Unexpected property (" + property + "); updating cache instead"); + Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead"); } } @@ -306,7 +307,7 @@ public final class ContentCaptureManagerService extends setFineTuneParamsFromDeviceConfig(); return; default: - Slog.i(mTag, "Ignoring change on " + key); + Slog.i(TAG, "Ignoring change on " + key); } } } @@ -333,7 +334,7 @@ public final class ContentCaptureManagerService extends ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT, (int) AbstractRemoteService.PERMANENT_BOUND_TIMEOUT_MS); if (verbose) { - Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): " + Slog.v(TAG, "setFineTuneParamsFromDeviceConfig(): " + "bufferSize=" + mDevCfgMaxBufferSize + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs @@ -352,7 +353,7 @@ public final class ContentCaptureManagerService extends verbose = ContentCaptureHelper.sVerbose; debug = ContentCaptureHelper.sDebug; if (verbose) { - Slog.v(mTag, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel + Slog.v(TAG, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel + ", debug=" + debug + ", verbose=" + verbose); } } @@ -367,7 +368,7 @@ public final class ContentCaptureManagerService extends private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) { if (verbose) { - Slog.v(mTag, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled); + Slog.v(TAG, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled); } final List<UserInfo> users = getSupportedUsers(); @@ -382,17 +383,17 @@ public final class ContentCaptureManagerService extends synchronized (mLock) { if (mDisabledByDeviceConfig == newDisabledValue) { if (verbose) { - Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue); + Slog.v(TAG, "setDisabledByDeviceConfig(): already " + newDisabledValue); } return; } mDisabledByDeviceConfig = newDisabledValue; - Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig); + Slog.i(TAG, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig); for (int i = 0; i < users.size(); i++) { final int userId = users.get(i).id; boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId); - Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user " + Slog.i(TAG, "setDisabledByDeviceConfig(): updating service for user " + userId + " to " + (disabled ? "'disabled'" : "'enabled'")); updateCachedServiceLocked(userId, disabled); } @@ -408,16 +409,16 @@ public final class ContentCaptureManagerService extends final boolean alreadyEnabled = !mDisabledBySettings.get(userId); if (!(enabled ^ alreadyEnabled)) { if (debug) { - Slog.d(mTag, "setContentCaptureFeatureEnabledForUser(): already " + enabled); + Slog.d(TAG, "setContentCaptureFeatureEnabledForUser(): already " + enabled); } return; } if (enabled) { - Slog.i(mTag, "setContentCaptureFeatureEnabled(): enabling service for user " + Slog.i(TAG, "setContentCaptureFeatureEnabled(): enabling service for user " + userId); mDisabledBySettings.delete(userId); } else { - Slog.i(mTag, "setContentCaptureFeatureEnabled(): disabling service for user " + Slog.i(TAG, "setContentCaptureFeatureEnabled(): disabling service for user " + userId); mDisabledBySettings.put(userId, true); } @@ -428,7 +429,7 @@ public final class ContentCaptureManagerService extends // Called by Shell command. void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) { - Slog.i(mTag, "destroySessions() for userId " + userId); + Slog.i(TAG, "destroySessions() for userId " + userId); enforceCallingPermissionForManagement(); synchronized (mLock) { @@ -451,7 +452,7 @@ public final class ContentCaptureManagerService extends // Called by Shell command. void listSessions(int userId, IResultReceiver receiver) { - Slog.i(mTag, "listSessions() for userId " + userId); + Slog.i(TAG, "listSessions() for userId " + userId); enforceCallingPermissionForManagement(); final Bundle resultData = new Bundle(); @@ -498,14 +499,14 @@ public final class ContentCaptureManagerService extends final int callingUid = Binder.getCallingUid(); final String serviceName = mServiceNameResolver.getServiceName(userId); if (serviceName == null) { - Slog.e(mTag, methodName + ": called by UID " + callingUid + Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but there's no service set for user " + userId); return false; } final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName); if (serviceComponent == null) { - Slog.w(mTag, methodName + ": invalid service name: " + serviceName); + Slog.w(TAG, methodName + ": invalid service name: " + serviceName); return false; } @@ -516,11 +517,11 @@ public final class ContentCaptureManagerService extends try { serviceUid = pm.getPackageUidAsUser(servicePackageName, UserHandle.getCallingUserId()); } catch (NameNotFoundException e) { - Slog.w(mTag, methodName + ": could not verify UID for " + serviceName); + Slog.w(TAG, methodName + ": could not verify UID for " + serviceName); return false; } if (callingUid != serviceUid) { - Slog.e(mTag, methodName + ": called by UID " + callingUid + ", but service UID is " + Slog.e(TAG, methodName + ": called by UID " + callingUid + ", but service UID is " + serviceUid); return false; } @@ -543,7 +544,7 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage())); } catch (RemoteException e2) { - Slog.w(mTag, "Unable to send security exception (" + e + "): ", e2); + Slog.w(TAG, "Unable to send security exception (" + e + "): ", e2); } } return true; @@ -628,7 +629,7 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_OK, bundleFor(connectedServiceComponentName)); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send service component name: " + e); + Slog.w(TAG, "Unable to send service component name: " + e); } } @@ -646,6 +647,7 @@ public final class ContentCaptureManagerService extends @Override public void shareData(@NonNull DataShareRequest request, + @NonNull ICancellationSignal clientCancellationSignal, @NonNull IDataShareWriteAdapter clientAdapter) { Preconditions.checkNotNull(request); Preconditions.checkNotNull(clientAdapter); @@ -661,13 +663,14 @@ public final class ContentCaptureManagerService extends try { clientAdapter.error(DataShareWriteAdapter.ERROR_CONCURRENT_REQUEST); } catch (RemoteException e) { - Slog.e(mTag, "Failed to send error message to client"); + Slog.e(TAG, "Failed to send error message to client"); } return; } service.onDataSharedLocked(request, - new DataShareCallbackDelegate(request, clientAdapter)); + new DataShareCallbackDelegate(request, clientCancellationSignal, + clientAdapter)); } } @@ -686,7 +689,7 @@ public final class ContentCaptureManagerService extends try { result.send(enabled ? RESULT_CODE_TRUE : RESULT_CODE_FALSE, /* resultData= */null); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e); + Slog.w(TAG, "Unable to send isContentCaptureFeatureEnabled(): " + e); } } @@ -706,7 +709,7 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_OK, bundleFor(componentName)); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send getServiceSettingsIntent(): " + e); + Slog.w(TAG, "Unable to send getServiceSettingsIntent(): " + e); } } @@ -727,13 +730,13 @@ public final class ContentCaptureManagerService extends try { result.send(RESULT_CODE_OK, bundleFor(conditions)); } catch (RemoteException e) { - Slog.w(mTag, "Unable to send getServiceComponentName(): " + e); + Slog.w(TAG, "Unable to send getServiceComponentName(): " + e); } } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return; + if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; boolean showHistory = true; if (args != null) { @@ -746,7 +749,7 @@ public final class ContentCaptureManagerService extends pw.println("Usage: dumpsys content_capture [--no-history]"); return; default: - Slog.w(mTag, "Ignoring invalid dump arg: " + arg); + Slog.w(TAG, "Ignoring invalid dump arg: " + arg); } } } @@ -843,7 +846,7 @@ public final class ContentCaptureManagerService extends final ComponentName componentName = ComponentName.unflattenFromString(serviceName); if (componentName == null) { - Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName); + Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName); mServicePackages.remove(userId); } else { mServicePackages.put(userId, componentName.getPackageName()); @@ -869,7 +872,7 @@ public final class ContentCaptureManagerService extends && packageName.equals(mServicePackages.get(userId))) { // No components whitelisted either, but let it go because it's the // service's own package - if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName); + if (verbose) Slog.v(TAG, "getOptionsForPackage() lite for " + packageName); return new ContentCaptureOptions(mDevCfgLoggingLevel); } } @@ -878,7 +881,7 @@ public final class ContentCaptureManagerService extends // Restrict what temporary services can whitelist if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) { if (!packageName.equals(mServicePackages.get(userId))) { - Slog.w(mTag, "Ignoring package " + packageName + " while using temporary " + Slog.w(TAG, "Ignoring package " + packageName + " while using temporary " + "service " + mServicePackages.get(userId)); return null; } @@ -887,7 +890,7 @@ public final class ContentCaptureManagerService extends if (!packageWhitelisted && whitelistedComponents == null) { // No can do! if (verbose) { - Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted"); + Slog.v(TAG, "getOptionsForPackage(" + packageName + "): not whitelisted"); } return null; } @@ -896,7 +899,7 @@ public final class ContentCaptureManagerService extends mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs, mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize, whitelistedComponents); - if (verbose) Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options); + if (verbose) Slog.v(TAG, "getOptionsForPackage(" + packageName + "): " + options); return options; } @@ -920,18 +923,21 @@ public final class ContentCaptureManagerService extends private class DataShareCallbackDelegate extends IDataShareCallback.Stub { @NonNull private final DataShareRequest mDataShareRequest; + @NonNull private final ICancellationSignal mClientCancellationSignal; @NonNull private final IDataShareWriteAdapter mClientAdapter; DataShareCallbackDelegate(@NonNull DataShareRequest dataShareRequest, + @NonNull ICancellationSignal clientCancellationSignal, @NonNull IDataShareWriteAdapter clientAdapter) { mDataShareRequest = dataShareRequest; + mClientCancellationSignal = clientCancellationSignal; mClientAdapter = clientAdapter; } @Override - public void accept(IDataShareReadAdapter serviceAdapter) - throws RemoteException { - Slog.i(mTag, "Data share request accepted by Content Capture service"); + public void accept(ICancellationSignal serviceCancellationSignal, + IDataShareReadAdapter serviceAdapter) throws RemoteException { + Slog.i(TAG, "Data share request accepted by Content Capture service"); Pair<ParcelFileDescriptor, ParcelFileDescriptor> clientPipe = createPipe(); if (clientPipe == null) { @@ -962,17 +968,14 @@ public final class ContentCaptureManagerService extends mClientAdapter.write(source_in); serviceAdapter.start(sink_out, cancellationSignalTransport); - // TODO(b/148264965): use cancellation signals for timeouts and cancelling CancellationSignal cancellationSignal = CancellationSignal.fromTransport(cancellationSignalTransport); cancellationSignal.setOnCancelListener(() -> { try { - // TODO(b/148264965): this should propagate with the cancellation signal to the - // client - mClientAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + mClientCancellationSignal.cancel(); } catch (RemoteException e) { - Slog.e(mTag, "Failed to propagate cancel operation to the caller", e); + Slog.e(TAG, "Failed to propagate cancel operation to the caller", e); } }); @@ -998,7 +1001,7 @@ public final class ContentCaptureManagerService extends fos.write(byteBuffer, 0 /* offset */, readBytes); } } catch (IOException e) { - Slog.e(mTag, "Failed to pipe client and service streams", e); + Slog.e(TAG, "Failed to pipe client and service streams", e); } }); @@ -1013,12 +1016,12 @@ public final class ContentCaptureManagerService extends && !source_out.getFileDescriptor().valid(); if (finishedSuccessfully) { - Slog.i(mTag, "Content capture data sharing session terminated " + Slog.i(TAG, "Content capture data sharing session terminated " + "successfully for package '" + mDataShareRequest.getPackageName() + "'"); } else { - Slog.i(mTag, "Reached the timeout of Content Capture data sharing session " + Slog.i(TAG, "Reached the timeout of Content Capture data sharing session " + "for package '" + mDataShareRequest.getPackageName() + "', terminating the pipe."); @@ -1029,14 +1032,14 @@ public final class ContentCaptureManagerService extends if (!finishedSuccessfully) { try { - mClientAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + mClientCancellationSignal.cancel(); } catch (RemoteException e) { - Slog.e(mTag, "Failed to call error() to client", e); + Slog.e(TAG, "Failed to cancel() the client operation", e); } try { - serviceAdapter.error(DataShareWriteAdapter.ERROR_UNKNOWN); + serviceCancellationSignal.cancel(); } catch (RemoteException e) { - Slog.e(mTag, "Failed to call error() to service", e); + Slog.e(TAG, "Failed to cancel() the service operation", e); } } } @@ -1045,7 +1048,7 @@ public final class ContentCaptureManagerService extends @Override public void reject() throws RemoteException { - Slog.i(mTag, "Data share request rejected by Content Capture service"); + Slog.i(TAG, "Data share request rejected by Content Capture service"); mClientAdapter.rejected(); } @@ -1055,19 +1058,19 @@ public final class ContentCaptureManagerService extends try { fileDescriptors = ParcelFileDescriptor.createPipe(); } catch (IOException e) { - Slog.e(mTag, "Failed to create a content capture data-sharing pipe", e); + Slog.e(TAG, "Failed to create a content capture data-sharing pipe", e); return null; } if (fileDescriptors.length != 2) { - Slog.e(mTag, "Failed to create a content capture data-sharing pipe, " + Slog.e(TAG, "Failed to create a content capture data-sharing pipe, " + "unexpected number of file descriptors"); return null; } if (!fileDescriptors[0].getFileDescriptor().valid() || !fileDescriptors[1].getFileDescriptor().valid()) { - Slog.e(mTag, "Failed to create a content capture data-sharing pipe, didn't " + Slog.e(TAG, "Failed to create a content capture data-sharing pipe, didn't " + "receive a pair of valid file descriptors."); return null; } @@ -1079,7 +1082,7 @@ public final class ContentCaptureManagerService extends try { fd.close(); } catch (IOException e) { - Slog.e(mTag, "Failed to close a file descriptor", e); + Slog.e(TAG, "Failed to close a file descriptor", e); } } diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java index cf996a50d5c7..fa916202d553 100644 --- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java +++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java @@ -567,39 +567,41 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { final long lastRxMs = mLastInfo.getControllerRxDurationMillis(); final long lastEnergy = mLastInfo.getControllerEnergyUsedMicroJoules(); - // We will modify the last info object to be the delta, and store the new - // WifiActivityEnergyInfo object as our last one. - final WifiActivityEnergyInfo delta = mLastInfo; - delta.setTimeSinceBootMillis(latest.getTimeSinceBootMillis()); - delta.setStackState(latest.getStackState()); + final long deltaTimeSinceBootMillis = latest.getTimeSinceBootMillis(); + final int deltaStackState = latest.getStackState(); + final long deltaControllerTxDurationMillis; + final long deltaControllerRxDurationMillis; + final long deltaControllerScanDurationMillis; + final long deltaControllerIdleDurationMillis; + final long deltaControllerEnergyUsedMicroJoules; final long txTimeMs = latest.getControllerTxDurationMillis() - lastTxMs; final long rxTimeMs = latest.getControllerRxDurationMillis() - lastRxMs; final long idleTimeMs = latest.getControllerIdleDurationMillis() - lastIdleMs; final long scanTimeMs = latest.getControllerScanDurationMillis() - lastScanMs; + final boolean wasReset; if (txTimeMs < 0 || rxTimeMs < 0 || scanTimeMs < 0 || idleTimeMs < 0) { // The stats were reset by the WiFi system (which is why our delta is negative). // Returns the unaltered stats. The total on time should not exceed the time - // duartion between reports. + // duration between reports. final long totalOnTimeMs = latest.getControllerTxDurationMillis() + latest.getControllerRxDurationMillis() + latest.getControllerIdleDurationMillis(); if (totalOnTimeMs <= timePeriodMs + MAX_WIFI_STATS_SAMPLE_ERROR_MILLIS) { - delta.setControllerEnergyUsedMicroJoules( - latest.getControllerEnergyUsedMicroJoules()); - delta.setControllerRxDurationMillis(latest.getControllerRxDurationMillis()); - delta.setControllerTxDurationMillis(latest.getControllerTxDurationMillis()); - delta.setControllerIdleDurationMillis(latest.getControllerIdleDurationMillis()); - delta.setControllerScanDurationMillis(latest.getControllerScanDurationMillis()); + deltaControllerEnergyUsedMicroJoules = latest.getControllerEnergyUsedMicroJoules(); + deltaControllerRxDurationMillis = latest.getControllerRxDurationMillis(); + deltaControllerTxDurationMillis = latest.getControllerTxDurationMillis(); + deltaControllerIdleDurationMillis = latest.getControllerIdleDurationMillis(); + deltaControllerScanDurationMillis = latest.getControllerScanDurationMillis(); } else { - delta.setControllerEnergyUsedMicroJoules(0); - delta.setControllerRxDurationMillis(0); - delta.setControllerTxDurationMillis(0); - delta.setControllerIdleDurationMillis(0); - delta.setControllerScanDurationMillis(0); + deltaControllerEnergyUsedMicroJoules = 0; + deltaControllerRxDurationMillis = 0; + deltaControllerTxDurationMillis = 0; + deltaControllerIdleDurationMillis = 0; + deltaControllerScanDurationMillis = 0; } - Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta); + wasReset = true; } else { final long totalActiveTimeMs = txTimeMs + rxTimeMs; long maxExpectedIdleTimeMs; @@ -634,21 +636,33 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync { maxExpectedIdleTimeMs = timePeriodMs - totalActiveTimeMs; } // These times seem to be the most reliable. - delta.setControllerTxDurationMillis(txTimeMs); - delta.setControllerRxDurationMillis(rxTimeMs); - delta.setControllerScanDurationMillis(scanTimeMs); + deltaControllerTxDurationMillis = txTimeMs; + deltaControllerRxDurationMillis = rxTimeMs; + deltaControllerScanDurationMillis = scanTimeMs; // WiFi calculates the idle time as a difference from the on time and the various // Rx + Tx times. There seems to be some missing time there because this sometimes // becomes negative. Just cap it at 0 and ensure that it is less than the expected idle // time from the difference in timestamps. // b/21613534 - delta.setControllerIdleDurationMillis( - Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs))); - delta.setControllerEnergyUsedMicroJoules( - Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy)); + deltaControllerIdleDurationMillis = + Math.min(maxExpectedIdleTimeMs, Math.max(0, idleTimeMs)); + deltaControllerEnergyUsedMicroJoules = + Math.max(0, latest.getControllerEnergyUsedMicroJoules() - lastEnergy); + wasReset = false; } mLastInfo = latest; + WifiActivityEnergyInfo delta = new WifiActivityEnergyInfo( + deltaTimeSinceBootMillis, + deltaStackState, + deltaControllerTxDurationMillis, + deltaControllerRxDurationMillis, + deltaControllerScanDurationMillis, + deltaControllerIdleDurationMillis, + deltaControllerEnergyUsedMicroJoules); + if (wasReset) { + Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + delta); + } return delta; } } diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index e7f537b897b9..4ddc391bd889 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -3451,6 +3451,7 @@ public class SyncManager { if (isLoggable) { Slog.v(TAG, " Dropping sync operation: account doesn't exist."); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: account doesn't exist."); return SYNC_OP_STATE_INVALID; } // Drop this sync request if it isn't syncable. @@ -3460,12 +3461,14 @@ public class SyncManager { Slog.v(TAG, " Dropping sync operation: " + "isSyncable == SYNCABLE_NO_ACCOUNT_ACCESS"); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS"); return SYNC_OP_STATE_INVALID_NO_ACCOUNT_ACCESS; } if (state == AuthorityInfo.NOT_SYNCABLE) { if (isLoggable) { Slog.v(TAG, " Dropping sync operation: isSyncable == NOT_SYNCABLE"); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: NOT_SYNCABLE"); return SYNC_OP_STATE_INVALID; } @@ -3484,6 +3487,7 @@ public class SyncManager { if (isLoggable) { Slog.v(TAG, " Dropping sync operation: disallowed by settings/network."); } + Slog.wtf(TAG, "SYNC_OP_STATE_INVALID: disallowed by settings/network"); return SYNC_OP_STATE_INVALID; } return SYNC_OP_STATE_VALID; diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index aa39926d2310..6ff276703443 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -87,7 +87,7 @@ public abstract class BrightnessMappingStrategy { } BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder( luxLevels, brightnessLevelsNits); - builder.setShortTermModelTimeout(shortTermModelTimeout); + builder.setShortTermModelTimeoutMillis(shortTermModelTimeout); builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO); return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange, @@ -739,10 +739,10 @@ public abstract class BrightnessMappingStrategy { @Override public long getShortTermModelTimeout() { - if (mConfig.getShortTermModelTimeout() >= 0) { - return mConfig.getShortTermModelTimeout(); + if (mConfig.getShortTermModelTimeoutMillis() >= 0) { + return mConfig.getShortTermModelTimeoutMillis(); } else { - return mDefaultConfig.getShortTermModelTimeout(); + return mDefaultConfig.getShortTermModelTimeoutMillis(); } } diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java index 214dcc0220ff..11fe15f0e12b 100644 --- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java @@ -46,7 +46,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; -import android.os.RemoteException; import android.util.Slog; import android.util.StatsLog; @@ -158,8 +157,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { @Override public void updateRuleSet( - String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) - throws RemoteException { + String version, ParceledListSlice<Rule> rules, IntentSender statusReceiver) { String ruleProvider = getCallerPackageNameOrThrow(); mHandler.post( @@ -190,7 +188,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { } @Override - public String getCurrentRuleSetVersion() throws RemoteException { + public String getCurrentRuleSetVersion() { getCallerPackageNameOrThrow(); RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata(); @@ -200,7 +198,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { } @Override - public String getCurrentRuleSetProvider() throws RemoteException { + public String getCurrentRuleSetProvider() { getCallerPackageNameOrThrow(); RuleMetadata ruleMetadata = mIntegrityFileManager.readMetadata(); @@ -212,14 +210,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { private void handleIntegrityVerification(Intent intent) { int verificationId = intent.getIntExtra(EXTRA_VERIFICATION_ID, -1); - // Fail early if we don't have any rules at all. - if (!mIntegrityFileManager.initialized()) { - Slog.i(TAG, "Rules not initialized. Skipping integrity check."); - mPackageManagerInternal.setIntegrityVerificationResult( - verificationId, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); - return; - } - try { Slog.i(TAG, "Received integrity verification intent " + intent.toString()); Slog.i(TAG, "Extras " + intent.getExtras()); diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java index 1a6b3d8b8411..79e69e15ff67 100644 --- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java +++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java @@ -76,6 +76,11 @@ public class RuleEvaluationEngine { } private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) { + if (!mIntegrityFileManager.initialized()) { + Slog.w(TAG, "Integrity rule files are not available. Evaluating only manifest rules."); + return new ArrayList<>(); + } + try { return mIntegrityFileManager.readRules(appInstallMetadata); } catch (Exception e) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e92f3ec5a836..eea59ca26f34 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -117,6 +117,7 @@ import android.app.AutomaticZenRule; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; +import android.app.ITransientNotificationCallback; import android.app.IUriGrantsManager; import android.app.Notification; import android.app.NotificationChannel; @@ -255,6 +256,9 @@ import com.android.server.lights.LightsManager; import com.android.server.lights.LogicalLight; import com.android.server.notification.ManagedServices.ManagedServiceInfo; import com.android.server.notification.ManagedServices.UserProfiles; +import com.android.server.notification.toast.CustomToastRecord; +import com.android.server.notification.toast.TextToastRecord; +import com.android.server.notification.toast.ToastRecord; import com.android.server.pm.PackageManagerService; import com.android.server.policy.PhoneWindowManager; import com.android.server.statusbar.StatusBarManagerInternal; @@ -295,8 +299,8 @@ import java.util.function.BiConsumer; /** {@hide} */ public class NotificationManagerService extends SystemService { - static final String TAG = "NotificationService"; - static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + public static final String TAG = "NotificationService"; + public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); public static final boolean ENABLE_CHILD_NOTIFICATIONS = SystemProperties.getBoolean("debug.child_notifs", true); @@ -393,6 +397,7 @@ public class NotificationManagerService extends SystemService { private PackageManager mPackageManagerClient; AudioManager mAudioManager; AudioManagerInternal mAudioManagerInternal; + // Can be null for wear @Nullable StatusBarManagerInternal mStatusBar; Vibrator mVibrator; private WindowManagerInternal mWindowManagerInternal; @@ -850,49 +855,6 @@ public class NotificationManagerService extends SystemService { out.endDocument(); } - private static final class ToastRecord - { - public final int pid; - public final String pkg; - public final IBinder token; - public final ITransientNotification callback; - public int duration; - public int displayId; - public Binder windowToken; - - ToastRecord(int pid, String pkg, IBinder token, ITransientNotification callback, - int duration, Binder windowToken, int displayId) { - this.pid = pid; - this.pkg = pkg; - this.token = token; - this.callback = callback; - this.duration = duration; - this.windowToken = windowToken; - this.displayId = displayId; - } - - void update(int duration) { - this.duration = duration; - } - - void dump(PrintWriter pw, String prefix, DumpFilter filter) { - if (filter != null && !filter.matches(pkg)) return; - pw.println(prefix + this); - } - - @Override - public final String toString() - { - return "ToastRecord{" - + Integer.toHexString(System.identityHashCode(this)) - + " pkg=" + pkg - + " token=" + token - + " callback=" + callback - + " duration=" + duration - + "}"; - } - } - @VisibleForTesting final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { @@ -2643,6 +2605,19 @@ public class NotificationManagerService extends SystemService { return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId; } + private ToastRecord getToastRecord(int pid, String packageName, IBinder token, + @Nullable CharSequence text, @Nullable ITransientNotification callback, int duration, + Binder windowToken, int displayId, + @Nullable ITransientNotificationCallback textCallback) { + if (callback == null) { + return new TextToastRecord(this, mStatusBar, pid, packageName, token, text, duration, + windowToken, displayId, textCallback); + } else { + return new CustomToastRecord(this, pid, packageName, token, callback, duration, + windowToken, displayId); + } + } + @VisibleForTesting NotificationManagerInternal getInternalService() { return mInternalService; @@ -2654,28 +2629,30 @@ public class NotificationManagerService extends SystemService { // ============================================================================ @Override - public void enqueueTextToast(String pkg, IBinder token, ITransientNotification callback, - int duration, int displayId) { - enqueueToast(pkg, token, callback, duration, displayId, false); + public void enqueueTextToast(String pkg, IBinder token, CharSequence text, int duration, + int displayId, @Nullable ITransientNotificationCallback callback) { + enqueueToast(pkg, token, text, null, duration, displayId, callback); } @Override public void enqueueToast(String pkg, IBinder token, ITransientNotification callback, int duration, int displayId) { - enqueueToast(pkg, token, callback, duration, displayId, true); + enqueueToast(pkg, token, null, callback, duration, displayId, null); } - private void enqueueToast(String pkg, IBinder token, ITransientNotification callback, - int duration, int displayId, boolean isCustomToast) { + private void enqueueToast(String pkg, IBinder token, @Nullable CharSequence text, + @Nullable ITransientNotification callback, int duration, int displayId, + @Nullable ITransientNotificationCallback textCallback) { if (DBG) { - Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback + Slog.i(TAG, "enqueueToast pkg=" + pkg + " token=" + token + " duration=" + duration + " displayId=" + displayId); } - if (pkg == null || callback == null || token == null) { - Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback + " token=" - + token); - return ; + if (pkg == null || (text == null && callback == null) + || (text != null && callback != null) || token == null) { + Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " text=" + text + " callback=" + + " token=" + token); + return; } final int callingUid = Binder.getCallingUid(); @@ -2703,7 +2680,7 @@ public class NotificationManagerService extends SystemService { return; } - if (isCustomToast && !appIsForeground && !isSystemToast) { + if (callback != null && !appIsForeground && !isSystemToast) { boolean block; try { block = mPlatformCompat.isChangeEnabledByPackageName( @@ -2745,28 +2722,28 @@ public class NotificationManagerService extends SystemService { int count = 0; final int N = mToastQueue.size(); for (int i=0; i<N; i++) { - final ToastRecord r = mToastQueue.get(i); - if (r.pkg.equals(pkg)) { - count++; - if (count >= MAX_PACKAGE_NOTIFICATIONS) { - Slog.e(TAG, "Package has already posted " + count + final ToastRecord r = mToastQueue.get(i); + if (r.pkg.equals(pkg)) { + count++; + if (count >= MAX_PACKAGE_NOTIFICATIONS) { + Slog.e(TAG, "Package has already posted " + count + " toasts. Not showing more. Package=" + pkg); - return; - } - } + return; + } + } } } Binder windowToken = new Binder(); mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId); - record = new ToastRecord(callingPid, pkg, token, callback, duration, - windowToken, displayId); + record = getToastRecord(callingPid, pkg, token, text, callback, duration, + windowToken, displayId, textCallback); mToastQueue.add(record); index = mToastQueue.size() - 1; - keepProcessAliveIfNeededLocked(callingPid); + keepProcessAliveForToastIfNeededLocked(callingPid); } // If it's at index 0, it's the current toast. It doesn't matter if it's - // new or just been updated. Call back and tell it to show itself. + // new or just been updated, show it. // If the callback fails, this will remove it from the list, so don't // assume that it's valid after this. if (index == 0) { @@ -6935,40 +6912,22 @@ public class NotificationManagerService extends SystemService { void showNextToastLocked() { ToastRecord record = mToastQueue.get(0); while (record != null) { - if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback); - try { - record.callback.show(record.windowToken); + if (record.show()) { scheduleDurationReachedLocked(record); return; - } catch (RemoteException e) { - Slog.w(TAG, "Object died trying to show notification " + record.callback - + " in package " + record.pkg); - // remove it from the list and let the process die - int index = mToastQueue.indexOf(record); - if (index >= 0) { - mToastQueue.remove(index); - } - keepProcessAliveIfNeededLocked(record.pid); - if (mToastQueue.size() > 0) { - record = mToastQueue.get(0); - } else { - record = null; - } } + int index = mToastQueue.indexOf(record); + if (index >= 0) { + mToastQueue.remove(index); + } + record = (mToastQueue.size() > 0) ? mToastQueue.get(0) : null; } } @GuardedBy("mToastQueue") void cancelToastLocked(int index) { ToastRecord record = mToastQueue.get(index); - try { - record.callback.hide(); - } catch (RemoteException e) { - Slog.w(TAG, "Object died trying to hide notification " + record.callback - + " in package " + record.pkg); - // don't worry about this, we're about to remove it from - // the list anyway - } + record.hide(); ToastRecord lastToast = mToastQueue.remove(index); @@ -6981,7 +6940,7 @@ public class NotificationManagerService extends SystemService { // one way or another. scheduleKillTokenTimeout(lastToast); - keepProcessAliveIfNeededLocked(record.pid); + keepProcessAliveForToastIfNeededLocked(record.pid); if (mToastQueue.size() > 0) { // Show the next one. If the callback fails, this will remove // it from the list, so don't assume that the list hasn't changed @@ -7004,7 +6963,7 @@ public class NotificationManagerService extends SystemService { { mHandler.removeCallbacksAndMessages(r); Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r); - int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; + int delay = r.getDuration() == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY; // Accessibility users may need longer timeout duration. This api compares original delay // with user's preference and return longer one. It returns original delay if there's no // preference. @@ -7053,13 +7012,21 @@ public class NotificationManagerService extends SystemService { return -1; } + /** + * Adjust process {@code pid} importance according to whether it has toasts in the queue or not. + */ + public void keepProcessAliveForToastIfNeeded(int pid) { + synchronized (mToastQueue) { + keepProcessAliveForToastIfNeededLocked(pid); + } + } + @GuardedBy("mToastQueue") - void keepProcessAliveIfNeededLocked(int pid) - { + private void keepProcessAliveForToastIfNeededLocked(int pid) { int toastCount = 0; // toasts from this pid ArrayList<ToastRecord> list = mToastQueue; - int N = list.size(); - for (int i=0; i<N; i++) { + int n = list.size(); + for (int i = 0; i < n; i++) { ToastRecord r = list.get(i); if (r.pid == pid) { toastCount++; diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java new file mode 100644 index 000000000000..aca6f4853597 --- /dev/null +++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification.toast; + +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.notification.NotificationManagerService.DBG; + +import android.app.ITransientNotification; +import android.os.Binder; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.notification.NotificationManagerService; + +/** + * Represents a custom toast, a toast whose view is provided by the app. + */ +public class CustomToastRecord extends ToastRecord { + private static final String TAG = NotificationManagerService.TAG; + + public final ITransientNotification callback; + + public CustomToastRecord( + NotificationManagerService notificationManager, int pid, String packageName, + IBinder token, ITransientNotification callback, int duration, Binder windowToken, + int displayId) { + super(notificationManager, pid, packageName, token, duration, windowToken, displayId); + this.callback = checkNotNull(callback); + } + + @Override + public boolean show() { + if (DBG) { + Slog.d(TAG, "Show pkg=" + pkg + " callback=" + callback); + } + try { + callback.show(windowToken); + return true; + } catch (RemoteException e) { + Slog.w(TAG, "Object died trying to show custom toast " + token + " in package " + + pkg); + mNotificationManager.keepProcessAliveForToastIfNeeded(pid); + return false; + } + } + + @Override + public void hide() { + try { + callback.hide(); + } catch (RemoteException e) { + Slog.w(TAG, "Object died trying to hide custom toast " + token + " in package " + + pkg); + + } + } + + @Override + public String toString() { + return "CustomToastRecord{" + + Integer.toHexString(System.identityHashCode(this)) + + " token=" + token + + " packageName=" + pkg + + " callback=" + callback + + " duration=" + getDuration() + + "}"; + } +} diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java new file mode 100644 index 000000000000..3c231b445f62 --- /dev/null +++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification.toast; + +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.notification.NotificationManagerService.DBG; + +import android.annotation.Nullable; +import android.app.ITransientNotificationCallback; +import android.os.Binder; +import android.os.IBinder; +import android.util.Slog; + +import com.android.server.notification.NotificationManagerService; +import com.android.server.statusbar.StatusBarManagerInternal; + +/** + * Represents a text toast, a toast rendered by the system that contains only text. + */ +public class TextToastRecord extends ToastRecord { + private static final String TAG = NotificationManagerService.TAG; + + public final CharSequence text; + @Nullable + private final StatusBarManagerInternal mStatusBar; + @Nullable + private final ITransientNotificationCallback mCallback; + + public TextToastRecord(NotificationManagerService notificationManager, + @Nullable StatusBarManagerInternal statusBarManager, int pid, String packageName, + IBinder token, CharSequence text, int duration, Binder windowToken, int displayId, + @Nullable ITransientNotificationCallback callback) { + super(notificationManager, pid, packageName, token, duration, windowToken, displayId); + mStatusBar = statusBarManager; + mCallback = callback; + this.text = checkNotNull(text); + } + + @Override + public boolean show() { + if (DBG) { + Slog.d(TAG, "Show pkg=" + pkg + " text=" + text); + } + if (mStatusBar == null) { + Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg); + return false; + } + mStatusBar.showToast(pkg, token, text, windowToken, getDuration(), mCallback); + return true; + } + + @Override + public void hide() { + // If it's null, show() would have returned false + checkNotNull(mStatusBar, "Cannot hide toast that wasn't shown"); + + mStatusBar.hideToast(pkg, token); + } + + @Override + public String toString() { + return "TextToastRecord{" + + Integer.toHexString(System.identityHashCode(this)) + + " token=" + token + + " packageName=" + pkg + + " text=" + text + + " duration=" + getDuration() + + "}"; + } +} diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java new file mode 100644 index 000000000000..ef75a6f5dd7b --- /dev/null +++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.notification.toast; + +import android.os.Binder; +import android.os.IBinder; + +import com.android.server.notification.NotificationManagerService; +import com.android.server.notification.NotificationManagerService.DumpFilter; + +import java.io.PrintWriter; + +/** + * Represents a toast, a transient notification. + */ +public abstract class ToastRecord { + public final int pid; + public final String pkg; + public final IBinder token; + public final int displayId; + public final Binder windowToken; + protected final NotificationManagerService mNotificationManager; + private int mDuration; + + protected ToastRecord( + NotificationManagerService notificationManager, + int pid, String pkg, IBinder token, int duration, + Binder windowToken, int displayId) { + this.mNotificationManager = notificationManager; + this.pid = pid; + this.pkg = pkg; + this.token = token; + this.windowToken = windowToken; + this.displayId = displayId; + mDuration = duration; + } + + /** + * This method is responsible for showing the toast represented by this object. + * + * @return True if it was successfully shown. + */ + public abstract boolean show(); + + /** + * This method is responsible for hiding the toast represented by this object. + */ + public abstract void hide(); + + /** + * Returns the duration of this toast, which can be {@link android.widget.Toast#LENGTH_SHORT} + * or {@link android.widget.Toast#LENGTH_LONG}. + */ + public int getDuration() { + return mDuration; + } + + /** + * Updates toast duration. + */ + public void update(int duration) { + mDuration = duration; + } + + /** + * Dumps a textual representation of this object. + */ + public void dump(PrintWriter pw, String prefix, DumpFilter filter) { + if (filter != null && !filter.matches(pkg)) { + return; + } + pw.println(prefix + this); + } +} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6c8e7b058346..de6b7d5af397 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2725,7 +2725,7 @@ public class PackageManagerService extends IPackageManager.Stub t.traceBegin("get system config"); SystemConfig systemConfig = SystemConfig.getInstance(); mAvailableFeatures = systemConfig.getAvailableFeatures(); - ApplicationPackageManager.invalidateHasSystemFeatureCache(); + ApplicationPackageManager.invalidateSysFeatureCache(); t.traceEnd(); mProtectedPackages = new ProtectedPackages(mContext); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index c3e7f62e4f31..da0d82047cbe 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -333,8 +333,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); } - private static final int USER_ACTIVITY_NOTIFICATION_DELAY = 200; - /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */ static final int WAITING_FOR_DRAWN_TIMEOUT = 1000; @@ -487,7 +485,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mPendingKeyguardOccluded; private boolean mKeyguardOccludedChanged; - private boolean mNotifyUserActivity; SleepToken mScreenOffSleepToken; volatile boolean mKeyguardOccluded; @@ -627,8 +624,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_LAUNCH_ASSIST = 23; private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 24; private static final int MSG_POWER_VERY_LONG_PRESS = 25; - private static final int MSG_NOTIFY_USER_ACTIVITY = 26; - private static final int MSG_RINGER_TOGGLE_CHORD = 27; + private static final int MSG_RINGER_TOGGLE_CHORD = 26; private class PolicyHandler extends Handler { @Override @@ -708,13 +704,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_HANDLE_ALL_APPS: launchAllAppsAction(); break; - case MSG_NOTIFY_USER_ACTIVITY: - removeMessages(MSG_NOTIFY_USER_ACTIVITY); - Intent intent = new Intent(ACTION_USER_ACTIVITY_NOTIFICATION); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL, - android.Manifest.permission.USER_ACTIVITY); - break; case MSG_RINGER_TOGGLE_CHORD: handleRingerChordGesture(); break; @@ -4892,13 +4881,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.sendEmptyMessage(MSG_HIDE_BOOT_MESSAGE); } - @Override - public void requestUserActivityNotification() { - if (!mNotifyUserActivity && !mHandler.hasMessages(MSG_NOTIFY_USER_ACTIVITY)) { - mNotifyUserActivity = true; - } - } - /** {@inheritDoc} */ @Override public void userActivity() { @@ -4920,12 +4902,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); } } - - if (mDefaultDisplayPolicy.isAwake() && mNotifyUserActivity) { - mHandler.sendEmptyMessageDelayed(MSG_NOTIFY_USER_ACTIVITY, - USER_ACTIVITY_NOTIFICATION_DELAY); - mNotifyUserActivity = false; - } } class ScreenLockTimeout implements Runnable { diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index c39da5fb0e99..e81214e44aff 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -1438,12 +1438,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { } /** - * Requests that the WindowManager sends - * WindowManagerPolicyConstants#ACTION_USER_ACTIVITY_NOTIFICATION on the next user activity. - */ - public void requestUserActivityNotification(); - - /** * Registers an IDisplayFoldListener. */ default void registerDisplayFoldListener(IDisplayFoldListener listener) {} diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 39d1a51c01de..92e5a01fc796 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -1268,6 +1268,7 @@ public class StatsPullAtomService extends SystemService { continue; } StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) .writeInt(managedProcess.uid) .writeString(managedProcess.processName) .writeInt(managedProcess.pid) diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index 95ffd8fe43d8..d88dccb9afeb 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -16,7 +16,10 @@ package com.android.server.statusbar; +import android.annotation.Nullable; +import android.app.ITransientNotificationCallback; import android.os.Bundle; +import android.os.IBinder; import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsetsController.Appearance; @@ -123,4 +126,15 @@ public interface StatusBarManagerInternal { /** @see com.android.internal.statusbar.IStatusBar#abortTransient */ void abortTransient(int displayId, @InternalInsetsType int[] types); + + /** + * @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence, + * IBinder, int, ITransientNotificationCallback) + */ + void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, + @Nullable ITransientNotificationCallback textCallback); + + /** @see com.android.internal.statusbar.IStatusBar#hideToast(String, IBinder) */ + void hideToast(String packageName, IBinder token); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 870c81fb5dc2..3f7d373c1848 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import android.annotation.Nullable; import android.app.ActivityThread; +import android.app.ITransientNotificationCallback; import android.app.Notification; import android.app.StatusBarManager; import android.content.ComponentName; @@ -500,6 +501,26 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D } catch (RemoteException ex) { } } } + + @Override + public void showToast(String packageName, IBinder token, CharSequence text, + IBinder windowToken, int duration, + @Nullable ITransientNotificationCallback callback) { + if (mBar != null) { + try { + mBar.showToast(packageName, token, text, windowToken, duration, callback); + } catch (RemoteException ex) { } + } + } + + @Override + public void hideToast(String packageName, IBinder token) { + if (mBar != null) { + try { + mBar.hideToast(packageName, token); + } catch (RemoteException ex) { } + } + } }; private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 36bee87a4ed3..bf89bab53f30 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2099,6 +2099,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * the above app windows specify orientation, the orientation is computed from the child window * container, e.g. {@link AppWindowToken#getOrientation(int)}. */ + @ScreenOrientation @Override int getOrientation() { final WindowManagerPolicy policy = mWmService.mPolicy; diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index f90f22423a2d..da773143f75c 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -1001,18 +1001,22 @@ public class DisplayRotation { * Given an orientation constant, returns the appropriate surface rotation, taking into account * sensors, docking mode, rotation lock, and other factors. * - * @param orientation An orientation constant, such as - * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. + * @param orientation An orientation constant, such as + * {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. * @param lastRotation The most recently used rotation. * @return The surface rotation to use. */ @VisibleForTesting - int rotationForOrientation(int orientation, int lastRotation) { - ProtoLog.v(WM_DEBUG_ORIENTATION, "rotationForOrientation(orient=%d, last=%d); user=%d %s", - orientation, lastRotation, mUserRotation, - mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED - ? "USER_ROTATION_LOCKED" : "" - ); + @Surface.Rotation + int rotationForOrientation(@ScreenOrientation int orientation, + @Surface.Rotation int lastRotation) { + ProtoLog.v(WM_DEBUG_ORIENTATION, + "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s", + ActivityInfo.screenOrientationToString(orientation), orientation, + Surface.rotationToString(lastRotation), lastRotation, + Surface.rotationToString(mUserRotation), mUserRotation, + mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED + ? "USER_ROTATION_LOCKED" : ""); if (isFixedToUserRotation()) { return mUserRotation; diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index bfb69172e9eb..e7aca898b19d 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -370,6 +370,11 @@ class ScreenRotationAnimation { } } + ProtoLog.d(WM_DEBUG_ORIENTATION, "Start rotation animation. customAnim=%s, " + + "mCurRotation=%s, mOriginalRotation=%s", + customAnim, Surface.rotationToString(mCurRotation), + Surface.rotationToString(mOriginalRotation)); + mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); mRotateExitAnimation.restrictDuration(maxAnimationDuration); mRotateExitAnimation.scaleCurrentDuration(animationScale); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 19461c52bd9e..9dba0d3ee051 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -367,6 +367,7 @@ class Task extends WindowContainer<WindowContainer> { * Display rotation as of the last time {@link #setBounds(Rect)} was called or this task was * moved to a new display. */ + @Surface.Rotation private int mRotation; // For comparison with DisplayContent bounds. diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 0ab5f91f0ce9..015b92c7cd03 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -1079,8 +1079,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< if (wc.fillsParent() || orientation != SCREEN_ORIENTATION_UNSPECIFIED) { // Use the orientation if the container fills its parent or requested an explicit // orientation that isn't SCREEN_ORIENTATION_UNSPECIFIED. - ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", toString(), - orientation, ActivityInfo.screenOrientationToString(orientation)); + ProtoLog.v(WM_DEBUG_ORIENTATION, "%s is requesting orientation %d (%s)", + wc.toString(), orientation, + ActivityInfo.screenOrientationToString(orientation)); return orientation; } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1360711ec97e..e13083007237 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7032,15 +7032,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver); } - @Override - public void requestUserActivityNotification() { - if (!checkCallingPermission(android.Manifest.permission.USER_ACTIVITY, - "requestUserActivityNotification()")) { - throw new SecurityException("Requires USER_ACTIVITY permission"); - } - mPolicy.requestUserActivityNotification(); - } - private final class LocalService extends WindowManagerInternal { @Override 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 1c88c40c3e2b..e724e60b3ae5 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 @@ -20,6 +20,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -27,6 +28,9 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.inOrder; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.android.server.job.JobSchedulerService.FREQUENT_INDEX; +import static com.android.server.job.JobSchedulerService.RARE_INDEX; +import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -568,6 +572,48 @@ public class ConnectivityControllerTest { assertFalse(controller.isStandbyExceptionRequestedLocked(UID_RED)); } + @Test + public void testRestrictedJobTracking() { + final JobStatus networked = createJobStatus(createJob() + .setEstimatedNetworkBytes(DataUnit.MEBIBYTES.toBytes(1), 0) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_CELLULAR), UID_RED); + final JobStatus unnetworked = createJobStatus(createJob(), UID_BLUE); + networked.setStandbyBucket(FREQUENT_INDEX); + unnetworked.setStandbyBucket(FREQUENT_INDEX); + + final Network cellularNet = new Network(101); + final NetworkCapabilities cellularCaps = + createCapabilities().addTransportType(TRANSPORT_CELLULAR); + reset(mConnManager); + answerNetwork(UID_RED, cellularNet, cellularCaps); + answerNetwork(UID_BLUE, cellularNet, cellularCaps); + + final ConnectivityController controller = new ConnectivityController(mService); + controller.maybeStartTrackingJobLocked(networked, null); + controller.maybeStartTrackingJobLocked(unnetworked, null); + + assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + + networked.setStandbyBucket(RESTRICTED_INDEX); + unnetworked.setStandbyBucket(RESTRICTED_INDEX); + controller.startTrackingRestrictedJobLocked(networked); + controller.startTrackingRestrictedJobLocked(unnetworked); + assertFalse(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + // Unnetworked shouldn't be affected by ConnectivityController since it doesn't have a + // connectivity constraint. + assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + + networked.setStandbyBucket(RARE_INDEX); + unnetworked.setStandbyBucket(RARE_INDEX); + controller.stopTrackingRestrictedJobLocked(networked); + controller.stopTrackingRestrictedJobLocked(unnetworked); + assertTrue(networked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + // Unnetworked shouldn't be affected by ConnectivityController since it doesn't have a + // connectivity constraint. + assertFalse(unnetworked.isConstraintSatisfied(JobStatus.CONSTRAINT_CONNECTIVITY)); + } + private void answerNetwork(int uid, Network net, NetworkCapabilities caps) { when(mConnManager.getActiveNetworkForUid(eq(uid))).thenReturn(net); when(mConnManager.getNetworkCapabilities(eq(net))).thenReturn(caps); diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java index 4d229efc8328..625766a97f13 100644 --- a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java +++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java @@ -157,6 +157,8 @@ public class WatchdogDiagnosticsTest { String expected = "TestThread2 annotated stack trace:\n" + " at java.lang.Object.wait(Native Method)\n" + + " at java.lang.Object.wait(Object.java:442)\n" + + " at java.lang.Object.wait(Object.java:568)\n" + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" + "WatchdogDiagnosticsTest.java:91)\n" + " - locked <HASH> (a java.lang.String)\n" + diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index 9a633931017e..770afb0a24d5 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -32,11 +32,9 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; 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.mockito.internal.verification.VerificationModeFactory.times; import android.content.BroadcastReceiver; import android.content.Context; @@ -59,7 +57,6 @@ import android.os.Message; import androidx.test.InstrumentationRegistry; import com.android.internal.R; -import com.android.server.LocalServices; import com.android.server.integrity.engine.RuleEvaluationEngine; import com.android.server.integrity.model.IntegrityCheckResult; import com.android.server.testutils.TestUtils; @@ -147,29 +144,8 @@ public class AppIntegrityManagerServiceImplTest { when(mIntegrityFileManager.initialized()).thenReturn(true); } - // This is not a test of the class, but more of a safeguard that we don't block any install in - // the default case. This is needed because we don't have any emergency kill switch to disable - // this component. - @Test - public void default_allow() throws Exception { - LocalServices.removeServiceForTest(PackageManagerInternal.class); - LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); - mService = AppIntegrityManagerServiceImpl.create(mMockContext); - ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = - ArgumentCaptor.forClass(BroadcastReceiver.class); - verify(mMockContext, times(2)) - .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any()); - Intent intent = makeVerificationIntent(); - - broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); - - // Since we are not mocking handler in this case, we must wait. - // 2 seconds should be a sensible timeout. - Thread.sleep(2000); - verify(mPackageManagerInternal) - .setIntegrityVerificationResult( - 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); - } + // TODO(b/148370598): Implement a test to validate that allow response is retuned when the test + // request times out. @Test public void updateRuleSet_notAuthorized() throws Exception { @@ -381,10 +357,10 @@ public class AppIntegrityManagerServiceImplTest { broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent); runJobInHandler(); + // The evaluation will still run since we still evaluate manifest based rules. verify(mPackageManagerInternal) .setIntegrityVerificationResult( 1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW); - verify(mSpyPackageManager, never()).getPackageArchiveInfo(any(), anyInt()); } @Test @@ -432,8 +408,8 @@ public class AppIntegrityManagerServiceImplTest { private Intent makeVerificationIntent() throws Exception { PackageInfo packageInfo = - mRealContext.getPackageManager().getPackageInfo(TEST_FRAMEWORK_PACKAGE, - PackageManager.GET_SIGNATURES); + mRealContext.getPackageManager() + .getPackageInfo(TEST_FRAMEWORK_PACKAGE, PackageManager.GET_SIGNATURES); doReturn(packageInfo) .when(mSpyPackageManager) .getPackageInfo(eq(INSTALLER), anyInt()); diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java index 99157024bb66..26b20965fbf5 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java @@ -16,12 +16,12 @@ package com.android.server.integrity.engine; -import static org.junit.Assert.assertEquals; +import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.content.integrity.AppInstallMetadata; -import android.content.integrity.Rule; import com.android.server.integrity.IntegrityFileManager; import com.android.server.integrity.model.IntegrityCheckResult; @@ -36,7 +36,6 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; @RunWith(JUnit4.class) @@ -68,33 +67,28 @@ public class RuleEvaluationEngineTest { public void testAllowedInstallers_empty() { Map<String, String> allowedInstallers = Collections.emptyMap(); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) - .getEffect()); + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(); + AppInstallMetadata appInstallMetadata3 = + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(); + + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); } @Test @@ -102,87 +96,100 @@ public class RuleEvaluationEngineTest { Map<String, String> allowedInstallers = Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(RANDOM_INSTALLER) - .setInstallerCertificate(RANDOM_INSTALLER_CERT) - .build(), - allowedInstallers) - .getEffect()); + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + + AppInstallMetadata appInstallMetadata3 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + + AppInstallMetadata appInstallMetadata4 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(RANDOM_INSTALLER_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); } @Test public void testAllowedInstallers_multipleElement() { - List<Rule> rules = new ArrayList<>(); Map<String, String> allowedInstallers = new HashMap<>(2); allowedInstallers.put(INSTALLER_1, INSTALLER_1_CERT); allowedInstallers.put(INSTALLER_2, INSTALLER_2_CERT); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.ALLOW, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_1) - .setInstallerCertificate(INSTALLER_2_CERT) - .build(), - allowedInstallers) - .getEffect()); - assertEquals( - IntegrityCheckResult.Effect.DENY, - mEngine.evaluate( - getAppInstallMetadataBuilder() - .setInstallerName(INSTALLER_2) - .setInstallerCertificate(INSTALLER_1_CERT) - .build(), - allowedInstallers) - .getEffect()); + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata3 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_2_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata3, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + + AppInstallMetadata appInstallMetadata4 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_2) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata4, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); + } + + @Test + public void manifestBasedRuleEvaluationWorksEvenWhenIntegrityFilesAreUnavailable() { + when(mIntegrityFileManager.initialized()).thenReturn(false); + + Map<String, String> allowedInstallers = + Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT); + + AppInstallMetadata appInstallMetadata1 = + getAppInstallMetadataBuilder() + .setInstallerName(INSTALLER_1) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata1, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.ALLOW); + + AppInstallMetadata appInstallMetadata2 = + getAppInstallMetadataBuilder() + .setInstallerName(RANDOM_INSTALLER) + .setInstallerCertificate(INSTALLER_1_CERT) + .build(); + assertThat(mEngine.evaluate(appInstallMetadata2, allowedInstallers).getEffect()) + .isEqualTo(IntegrityCheckResult.Effect.DENY); } /** Returns a builder with all fields filled with some dummy data. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 9f45044c6a60..3a689246205d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -406,10 +406,6 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public void requestUserActivityNotification() { - } - - @Override public boolean setAodShowing(boolean aodShowing) { return false; } diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index acf51f3856d3..f54f8d1f5832 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -265,6 +265,29 @@ public final class Call { public static final String EVENT_HANDOVER_FAILED = "android.telecom.event.HANDOVER_FAILED"; + + /** + * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this + * call because they have declined to answer it. This typically means that they are unable + * to answer the call at this time and would prefer it be sent to voicemail. + */ + public static final int REJECT_REASON_DECLINED = 1; + + /** + * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this + * call because it is an unwanted call. This allows the user to indicate that they are + * rejecting a call because it is likely a nuisance call. + */ + public static final int REJECT_REASON_UNWANTED = 2; + + /** + * @hide + */ + @IntDef(prefix = { "REJECT_REASON_" }, + value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED}) + @Retention(RetentionPolicy.SOURCE) + public @interface RejectReason {}; + public static class Details { /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -1520,6 +1543,16 @@ public final class Call { } /** + * Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the + * user has chosen to reject the call and has indicated a reason why the call is being rejected. + * + * @param rejectReason the reason the call is being rejected. + */ + public void reject(@RejectReason int rejectReason) { + mInCallAdapter.rejectCall(mTelecomCallId, rejectReason); + } + + /** * Instructs this {@code Call} to disconnect. */ public void disconnect() { diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index c934625f588b..72c66d20548a 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -3037,6 +3037,17 @@ public abstract class Connection extends Conferenceable { public void onReject() {} /** + * Notifies this Connection, which is in {@link #STATE_RINGING}, of a request to reject. + * <p> + * For managed {@link ConnectionService}s, this will be called when the user rejects a call via + * the default dialer's {@link InCallService} using {@link Call#reject(int)}. + * @param rejectReason the reason the user provided for rejecting the call. + */ + public void onReject(@android.telecom.Call.RejectReason int rejectReason) { + // to be implemented by ConnectionService. + } + + /** * Notifies this Connection, which is in {@link #STATE_RINGING}, of * a request to reject with a message. */ diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 440f044fdcf7..00c2918837ac 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -194,6 +194,7 @@ public abstract class ConnectionService extends Service { private static final int MSG_CREATE_CONFERENCE = 35; private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36; private static final int MSG_CREATE_CONFERENCE_FAILED = 37; + private static final int MSG_REJECT_WITH_REASON = 38; private static Connection sNullConnection; @@ -450,6 +451,21 @@ public abstract class ConnectionService extends Service { } @Override + public void rejectWithReason(String callId, + @android.telecom.Call.RejectReason int rejectReason, Session.Info sessionInfo) { + Log.startSession(sessionInfo, SESSION_REJECT); + try { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = callId; + args.argi1 = rejectReason; + args.arg2 = Log.createSubsession(); + mHandler.obtainMessage(MSG_REJECT_WITH_REASON, args).sendToTarget(); + } finally { + Log.endSession(); + } + } + + @Override public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) { Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE); try { @@ -1053,6 +1069,17 @@ public abstract class ConnectionService extends Service { } break; } + case MSG_REJECT_WITH_REASON: { + SomeArgs args = (SomeArgs) msg.obj; + Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT); + try { + reject((String) args.arg1, args.argi1); + } finally { + args.recycle(); + Log.endSession(); + } + break; + } case MSG_REJECT_WITH_MESSAGE: { SomeArgs args = (SomeArgs) msg.obj; Log.continueSession((Session) args.arg3, @@ -1981,6 +2008,11 @@ public abstract class ConnectionService extends Service { findConnectionForAction(callId, "reject").onReject(rejectWithMessage); } + private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) { + Log.d(this, "reject %s with reason %d", callId, rejectReason); + findConnectionForAction(callId, "reject").onReject(rejectReason); + } + private void silence(String callId) { Log.d(this, "silence %s", callId); findConnectionForAction(callId, "silence").onSilence(); diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index 261246818f1d..594c1eb392b3 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -89,6 +89,19 @@ public final class InCallAdapter { } /** + * Instructs Telecom to reject the specified call. + * + * @param callId The identifier of the call to reject. + * @param rejectReason The reason the call was rejected. + */ + public void rejectCall(String callId, @Call.RejectReason int rejectReason) { + try { + mAdapter.rejectCallWithReason(callId, rejectReason); + } catch (RemoteException e) { + } + } + + /** * Instructs Telecom to disconnect the specified call. * * @param callId The identifier of the call to disconnect. diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl index 96f2483f32f9..4249dff151c7 100644 --- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl +++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl @@ -77,6 +77,8 @@ oneway interface IConnectionService { void reject(String callId, in Session.Info sessionInfo); + void rejectWithReason(String callId, int rejectReason, in Session.Info sessionInfo); + void rejectWithMessage(String callId, String message, in Session.Info sessionInfo); void disconnect(String callId, in Session.Info sessionInfo); diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 60745e40aa77..eb2d714fe3f4 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -34,6 +34,8 @@ oneway interface IInCallAdapter { void rejectCall(String callId, boolean rejectWithMessage, String textMessage); + void rejectCallWithReason(String callId, int rejectReason); + void disconnectCall(String callId); void holdCall(String callId); diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java index 9b4292f42172..704e5aa78188 100644 --- a/telephony/java/android/telephony/ImsManager.java +++ b/telephony/java/android/telephony/ImsManager.java @@ -27,11 +27,7 @@ import android.telephony.SubscriptionManager; /** * Provides access to information about Telephony IMS services on the device. - * - * @hide */ -@SystemApi -@TestApi @SystemService(Context.TELEPHONY_IMS_SERVICE) public class ImsManager { @@ -45,7 +41,10 @@ public class ImsManager { * <p class="note"> * Carrier applications may listen to this broadcast to be notified of possible IMS provisioning * issues. + * @hide */ + @SystemApi + @TestApi // Moved from TelephonyIntents, need to keep backwards compatibility with OEM apps that have // this value hard-coded in BroadcastReceiver. @SuppressLint("ActionValue") @@ -104,7 +103,10 @@ public class ImsManager { * @param subscriptionId The ID of the subscription that this ImsRcsManager will use. * @throws IllegalArgumentException if the subscription is invalid. * @return a ImsRcsManager instance with the specific subscription ID. + * @hide */ + @SystemApi + @TestApi @NonNull public ImsRcsManager getImsRcsManager(int subscriptionId) { if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index cb3f0f92625e..643f452d2e75 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -61,7 +61,6 @@ public final class ImsException extends Exception { * This is a configuration error and there should be no retry. The subscription used for this * operation is either invalid or has become inactive. The active subscriptions can be queried * with {@link SubscriptionManager#getActiveSubscriptionInfoList()}. - * @hide */ public static final int CODE_ERROR_INVALID_SUBSCRIPTION = 3; diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 5fdef8307d42..3341fa74d672 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -56,7 +56,8 @@ import java.util.function.Consumer; * registration and MmTel capability status callbacks, as well as query/modify user settings for the * associated subscription. * - * @see #createForSubscriptionId(int) + * Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an instance of this + * manager. */ public class ImsMmTelManager implements RegistrationManager { @@ -228,8 +229,13 @@ public class ImsMmTelManager implements RegistrationManager { * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). * * @throws IllegalArgumentException if the subscription is invalid. - * + * @deprecated Use {@link android.telephony.ims.ImsManager#getImsMmTelManager(int)} to get an + * instance of this class. + * @hide */ + @SystemApi + @TestApi + @Deprecated @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). @RequiresPermission(anyOf = { android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, @@ -245,7 +251,7 @@ public class ImsMmTelManager implements RegistrationManager { } /** - * Only visible for testing, use {@link #createForSubscriptionId(int)} instead. + * Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead. * @hide */ @VisibleForTesting @@ -255,7 +261,7 @@ public class ImsMmTelManager implements RegistrationManager { /** * Registers a {@link RegistrationCallback} with the system, which will provide registration - * updates for the subscription specified in {@link #createForSubscriptionId(int)}. Use + * updates for the subscription specified in {@link ImsManager#getImsMmTelManager(int)}. Use * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up. * @@ -453,7 +459,7 @@ public class ImsMmTelManager implements RegistrationManager { /** * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service * availability updates for the subscription specified in - * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)} + * {@link ImsManager#getImsMmTelManager(int)}. The method {@see #isAvailable(int, int)} * can also be used to query this information at any time. * * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index 62bc2ae44573..2b3072eefe2e 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -60,9 +60,10 @@ import com.android.internal.annotations.VisibleForTesting; * The telephony framework will then bind to the ImsService you have defined in your manifest * if you are either: * 1) Defined as the default ImsService for the device in the device overlay using - * "config_ims_package". + * "config_ims_mmtel_package" or "config_ims_rcs_package". * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using - * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}. + * {@link CarrierConfigManager#KEY_CONFIG_IMS_MMTEL_PACKAGE_OVERRIDE_STRING} or + * {@link CarrierConfigManager#KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING}. * * There are two ways to define to the platform which {@link ImsFeature}s this {@link ImsService} * supports, dynamic or static definitions. diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 3e2903fa6f47..57b9b7a30f8c 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -16,10 +16,11 @@ package android.telephony.ims; -import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; @@ -37,6 +38,7 @@ import java.util.Map; * @hide */ @SystemApi +@TestApi public final class RcsContactUceCapability implements Parcelable { /** Supports 1-to-1 chat */ @@ -99,11 +101,16 @@ public final class RcsContactUceCapability implements Parcelable { public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27); /** Supports the unidirectional plug-ins framework. */ public static final int CAPABILITY_PLUG_IN = (1 << 28); + /** Supports standalone Chatbot communication. */ + public static final int CAPABILITY_STANDALONE_CHAT_BOT = (1 << 29); + /** Supports MMTEL based call composer. */ + public static final int CAPABILITY_MMTEL_CALL_COMPOSER = (1 << 30); + /** @hide*/ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "CAPABILITY_", flag = true, value = { + @LongDef(prefix = "CAPABILITY_", flag = true, value = { CAPABILITY_CHAT_STANDALONE, CAPABILITY_CHAT_SESSION, CAPABILITY_CHAT_SESSION_STORE_FORWARD, @@ -132,7 +139,9 @@ public final class RcsContactUceCapability implements Parcelable { CAPABILITY_SHARED_SKETCH, CAPABILITY_CHAT_BOT, CAPABILITY_CHAT_BOT_ROLE, - CAPABILITY_PLUG_IN + CAPABILITY_PLUG_IN, + CAPABILITY_STANDALONE_CHAT_BOT, + CAPABILITY_MMTEL_CALL_COMPOSER }) public @interface CapabilityFlag {} @@ -159,11 +168,11 @@ public final class RcsContactUceCapability implements Parcelable { * @param type The capability to map to a service URI that is different from the contact's * URI. */ - public @NonNull Builder add(@CapabilityFlag int type, @NonNull Uri serviceUri) { + public @NonNull Builder add(@CapabilityFlag long type, @NonNull Uri serviceUri) { mCapabilities.mCapabilities |= type; // Put each of these capabilities into the map separately. - for (int shift = 0; shift < Integer.SIZE; shift++) { - int cap = type & (1 << shift); + for (long shift = 0; shift < Integer.SIZE; shift++) { + long cap = type & (1 << shift); if (cap != 0) { mCapabilities.mServiceMap.put(cap, serviceUri); // remove that capability from the field. @@ -181,7 +190,7 @@ public final class RcsContactUceCapability implements Parcelable { * Add a UCE capability flag that this contact supports. * @param type the capability that the contact supports. */ - public @NonNull Builder add(@CapabilityFlag int type) { + public @NonNull Builder add(@CapabilityFlag long type) { mCapabilities.mCapabilities |= type; return this; } @@ -207,7 +216,7 @@ public final class RcsContactUceCapability implements Parcelable { private final Uri mContactUri; private long mCapabilities; private List<String> mExtensionTags = new ArrayList<>(); - private Map<Integer, Uri> mServiceMap = new HashMap<>(); + private Map<Long, Uri> mServiceMap = new HashMap<>(); /** * Use {@link Builder} to build an instance of this interface. @@ -225,7 +234,7 @@ public final class RcsContactUceCapability implements Parcelable { // read mServiceMap as key,value pair int mapSize = in.readInt(); for (int i = 0; i < mapSize; i++) { - mServiceMap.put(in.readInt(), in.readParcelable(Uri.class.getClassLoader())); + mServiceMap.put(in.readLong(), in.readParcelable(Uri.class.getClassLoader())); } } @@ -250,8 +259,8 @@ public final class RcsContactUceCapability implements Parcelable { // write mServiceMap as key,value pairs int mapSize = mServiceMap.keySet().size(); out.writeInt(mapSize); - for (int key : mServiceMap.keySet()) { - out.writeInt(key); + for (long key : mServiceMap.keySet()) { + out.writeLong(key); out.writeParcelable(mServiceMap.get(key), 0); } } @@ -266,7 +275,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param type The capability flag to query. * @return true if the capability flag specified is set, false otherwise. */ - public boolean isCapable(@CapabilityFlag int type) { + public boolean isCapable(@CapabilityFlag long type) { return (mCapabilities & type) > 0; } @@ -290,13 +299,13 @@ public final class RcsContactUceCapability implements Parcelable { * <p> * This will typically be the contact {@link Uri} available via {@link #getContactUri()} unless * a different service {@link Uri} was associated with this capability using - * {@link Builder#add(int, Uri)}. + * {@link Builder#add(long, Uri)}. * * @return a String containing the {@link Uri} associated with the service tag or * {@code null} if this capability is not set as capable. - * @see #isCapable(int) + * @see #isCapable(long) */ - public @Nullable Uri getServiceUri(@CapabilityFlag int type) { + public @Nullable Uri getServiceUri(@CapabilityFlag long type) { Uri result = mServiceMap.getOrDefault(type, null); // If the capability is capable, but does not have a service URI associated, use the default // contact URI. diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 72167761c88d..72a00ce052da 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -174,7 +174,6 @@ public class RcsUceAdapter { * Provides a one-time callback for the response to a UCE request. After this callback is called * by the framework, the reference to this callback will be discarded on the service side. * @see #requestCapabilities(Executor, List, CapabilitiesCallback) - * @hide */ public static class CapabilitiesCallback { @@ -226,10 +225,9 @@ public class RcsUceAdapter { * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not * available. This can happen if the ImsService has crashed, for example, or if the subscription * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. - * @hide */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void requestCapabilities(@CallbackExecutor Executor executor, + public void requestCapabilities(@NonNull @CallbackExecutor Executor executor, @NonNull List<Uri> contactNumbers, @NonNull CapabilitiesCallback c) throws ImsException { if (c == null) { @@ -289,7 +287,6 @@ public class RcsUceAdapter { * {@link RcsUceAdapter} is valid, but the ImsService associated with the subscription is not * available. This can happen if the ImsService has crashed, for example, or if the subscription * becomes inactive. See {@link ImsException#getCode()} for more information on the error codes. - * @hide */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @PublishState int getUcePublishState() throws ImsException { diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index f3aea4978971..a3ce1b585f76 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -513,7 +513,7 @@ public class MmTelFeature extends ImsFeature { * @param callProfile The {@link ImsCallProfile} IMS call profile with details. * This can be null if no call information is available for the rejected call. * @param reason The {@link ImsReasonInfo} call rejection reason. - * * @hide + * @hide */ @SystemApi @TestApi public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile, diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 884a0bc7c06e..8e67621b2ea3 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -349,9 +349,8 @@ public class RcsFeature extends ImsFeature { * * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if * it is supported by the device. - * @hide */ - public RcsSipOptionsImplBase getOptionsExchangeImpl() { + public @NonNull RcsSipOptionsImplBase getOptionsExchangeImpl() { // Base Implementation, override to implement functionality return new RcsSipOptionsImplBase(); } @@ -365,9 +364,8 @@ public class RcsFeature extends ImsFeature { * * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence * exchange if it is supported by the device. - * @hide */ - public RcsPresenceExchangeImplBase getPresenceExchangeImpl() { + public @NonNull RcsPresenceExchangeImplBase getPresenceExchangeImpl() { // Base Implementation, override to implement functionality. return new RcsPresenceExchangeImplBase(); } diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java index f4367da4a4dc..e8f69ea64a22 100644 --- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java @@ -410,6 +410,13 @@ public class ImsCallSessionImplBase implements AutoCloseable { * Rejects an incoming call or session update. * * @param reason reason code to reject an incoming call, defined in {@link ImsReasonInfo}. + * The {@link android.telecom.InCallService} (dialer app) can use the + * {@link android.telecom.Call#reject(int)} API to reject a call while specifying + * a user-indicated reason for rejecting the call. + * Normal call declines ({@link android.telecom.Call#REJECT_REASON_DECLINED}) will + * map to {@link ImsReasonInfo#CODE_USER_DECLINE}. + * Unwanted calls ({@link android.telecom.Call#REJECT_REASON_UNWANTED}) will map + * to {@link ImsReasonInfo#CODE_SIP_USER_MARKED_UNWANTED}. * {@link ImsCallSession.Listener#callSessionStartFailed} */ public void reject(int reason) { diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java index fda295a27111..a24af2f74e27 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchange.java @@ -17,6 +17,8 @@ package android.telephony.ims.stub; import android.annotation.IntDef; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.RemoteException; import android.telephony.ims.ImsException; import android.telephony.ims.aidl.IRcsFeatureListener; @@ -32,6 +34,8 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@SystemApi +@TestApi public class RcsCapabilityExchange { /** Service is unknown. */ diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java index bb034489a296..f200ea2af2bc 100644 --- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java @@ -18,6 +18,8 @@ package android.telephony.ims.stub; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.ImsException; @@ -37,6 +39,8 @@ import java.util.List; * * @hide */ +@SystemApi +@TestApi public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { private static final String LOG_TAG = "RcsPresenceExchangeIB"; diff --git a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java index 1c68fc08529e..355c4dde75d8 100644 --- a/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsSipOptionsImplBase.java @@ -19,6 +19,8 @@ package android.telephony.ims.stub; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.ImsException; @@ -35,6 +37,8 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ +@SystemApi +@TestApi public class RcsSipOptionsImplBase extends RcsCapabilityExchange { private static final String LOG_TAG = "RcsSipOptionsImplBase"; @@ -69,6 +73,11 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { */ public static final int RESPONSE_DOES_NOT_EXIST_ANYWHERE = 4; + /** + * Indicates that the remote user responded with a 400 BAD REQUEST response. + */ + public static final int RESPONSE_BAD_REQUEST = 5; + /** @hide*/ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = "RESPONSE_", value = { @@ -77,7 +86,8 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { RESPONSE_TEMPORARILY_UNAVAILABLE, RESPONSE_REQUEST_TIMEOUT, RESPONSE_NOT_FOUND, - RESPONSE_DOES_NOT_EXIST_ANYWHERE + RESPONSE_DOES_NOT_EXIST_ANYWHERE, + RESPONSE_BAD_REQUEST }) public @interface SipResponseCode {} @@ -188,7 +198,6 @@ public class RcsSipOptionsImplBase extends RcsCapabilityExchange { * @param reason A non-null String containing the reason associated with the SIP code. * @param operationToken The token provided by the framework when * {@link #onRemoteCapabilityRequest(Uri, RcsContactUceCapability, int)} was called. - * */ public void respondToCapabilityRequestWithError(@NonNull Uri contactUri, @SipResponseCode int code, @NonNull String reason, int operationToken) { diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index c34fd777d156..d41a6c889afb 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -315,4 +315,10 @@ public class TelephonyIntents { */ public static final String ACTION_LINE1_NUMBER_ERROR_DETECTED = "com.android.internal.telephony.ACTION_LINE1_NUMBER_ERROR_DETECTED"; + + /** + * Broadcast sent when a user activity is detected. + */ + public static final String ACTION_USER_ACTIVITY_NOTIFICATION = + "android.intent.action.USER_ACTIVITY_NOTIFICATION"; } diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java index ae55a75d7e67..8559cb9f51f7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/SeamlessAppRotationTest.java @@ -30,10 +30,12 @@ import android.graphics.Rect; import android.view.Surface; import androidx.test.InstrumentationRegistry; +import androidx.test.filters.FlakyTest; import androidx.test.filters.LargeTest; import org.junit.Before; import org.junit.FixMethodOrder; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.MethodSorters; @@ -50,6 +52,8 @@ import java.util.Collection; @LargeTest @RunWith(Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@FlakyTest(bugId = 147659548) +@Ignore("Waiting bug feedback") public class SeamlessAppRotationTest extends FlickerTestBase { private int mBeginRotation; private int mEndRotation; diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 419bcb107013..f8d48c5403f7 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -178,7 +178,7 @@ public class WifiInfo implements Parcelable { * If connected to a network suggestion or specifier, store the package name of the app, * else null. */ - private String mAppPackageName; + private String mRequestingPackageName; /** * Running total count of lost (not ACKed) transmitted unicast data packets. @@ -201,68 +201,68 @@ public class WifiInfo implements Parcelable { */ public long rxSuccess; - private double mTxBadRate; + private double mLostTxPacketsPerSecond; /** * Average rate of lost transmitted packets, in units of packets per second. * @hide */ @SystemApi - public double getTxBadRate() { - return mTxBadRate; + public double getLostTxPacketsPerSecond() { + return mLostTxPacketsPerSecond; } /** @hide */ - public void setTxBadRate(double txBadRate) { - mTxBadRate = txBadRate; + public void setLostTxPacketsPerSecond(double lostTxPacketsPerSecond) { + mLostTxPacketsPerSecond = lostTxPacketsPerSecond; } - private double mTxRetriesRate; + private double mTxRetriedTxPacketsPerSecond; /** * Average rate of transmitted retry packets, in units of packets per second. * @hide */ @SystemApi - public double getTxRetriesRate() { - return mTxRetriesRate; + public double getRetriedTxPacketsPerSecond() { + return mTxRetriedTxPacketsPerSecond; } /** @hide */ - public void setTxRetriesRate(double txRetriesRate) { - mTxRetriesRate = txRetriesRate; + public void setRetriedTxPacketsRate(double txRetriedTxPacketsPerSecond) { + mTxRetriedTxPacketsPerSecond = txRetriedTxPacketsPerSecond; } - private double mTxSuccessRate; + private double mSuccessfulTxPacketsPerSecond; /** * Average rate of successfully transmitted unicast packets, in units of packets per second. * @hide */ @SystemApi - public double getTxSuccessRate() { - return mTxSuccessRate; + public double getSuccessfulTxPacketsPerSecond() { + return mSuccessfulTxPacketsPerSecond; } /** @hide */ - public void setTxSuccessRate(double txSuccessRate) { - mTxSuccessRate = txSuccessRate; + public void setSuccessfulTxPacketsPerSecond(double successfulTxPacketsPerSecond) { + mSuccessfulTxPacketsPerSecond = successfulTxPacketsPerSecond; } - private double mRxSuccessRate; + private double mSuccessfulRxPacketsPerSecond; /** * Average rate of received unicast data packets, in units of packets per second. * @hide */ @SystemApi - public double getRxSuccessRate() { - return mRxSuccessRate; + public double getSuccessfulRxPacketsPerSecond() { + return mSuccessfulRxPacketsPerSecond; } /** @hide */ - public void setRxSuccessRate(double rxSuccessRate) { - mRxSuccessRate = rxSuccessRate; + public void setSuccessfulRxPacketsPerSecond(double successfulRxPacketsPerSecond) { + mSuccessfulRxPacketsPerSecond = successfulRxPacketsPerSecond; } /** @hide */ @@ -319,17 +319,17 @@ public class WifiInfo implements Parcelable { setMeteredHint(false); setEphemeral(false); setOsuAp(false); - setAppPackageName(null); + setRequestingPackageName(null); setFQDN(null); setProviderFriendlyName(null); txBad = 0; txSuccess = 0; rxSuccess = 0; txRetries = 0; - mTxBadRate = 0; - mTxSuccessRate = 0; - mRxSuccessRate = 0; - mTxRetriesRate = 0; + mLostTxPacketsPerSecond = 0; + mSuccessfulTxPacketsPerSecond = 0; + mSuccessfulRxPacketsPerSecond = 0; + mTxRetriedTxPacketsPerSecond = 0; score = 0; } @@ -353,8 +353,8 @@ public class WifiInfo implements Parcelable { mMeteredHint = source.mMeteredHint; mEphemeral = source.mEphemeral; mTrusted = source.mTrusted; - mAppPackageName = - source.mAppPackageName; + mRequestingPackageName = + source.mRequestingPackageName; mOsuAp = source.mOsuAp; mFqdn = source.mFqdn; mProviderFriendlyName = source.mProviderFriendlyName; @@ -362,10 +362,10 @@ public class WifiInfo implements Parcelable { txRetries = source.txRetries; txSuccess = source.txSuccess; rxSuccess = source.rxSuccess; - mTxBadRate = source.mTxBadRate; - mTxRetriesRate = source.mTxRetriesRate; - mTxSuccessRate = source.mTxSuccessRate; - mRxSuccessRate = source.mRxSuccessRate; + mLostTxPacketsPerSecond = source.mLostTxPacketsPerSecond; + mTxRetriedTxPacketsPerSecond = source.mTxRetriedTxPacketsPerSecond; + mSuccessfulTxPacketsPerSecond = source.mSuccessfulTxPacketsPerSecond; + mSuccessfulRxPacketsPerSecond = source.mSuccessfulRxPacketsPerSecond; score = source.score; mWifiStandard = source.mWifiStandard; mMaxSupportedTxLinkSpeed = source.mMaxSupportedTxLinkSpeed; @@ -777,8 +777,8 @@ public class WifiInfo implements Parcelable { } /** {@hide} */ - public void setAppPackageName(@Nullable String packageName) { - mAppPackageName = packageName; + public void setRequestingPackageName(@Nullable String packageName) { + mRequestingPackageName = packageName; } /** @@ -788,8 +788,8 @@ public class WifiInfo implements Parcelable { * @hide */ @SystemApi - public @Nullable String getAppPackageName() { - return mAppPackageName; + public @Nullable String getRequestingPackageName() { + return mRequestingPackageName; } @@ -956,16 +956,16 @@ public class WifiInfo implements Parcelable { dest.writeInt(mTrusted ? 1 : 0); dest.writeInt(score); dest.writeLong(txSuccess); - dest.writeDouble(mTxSuccessRate); + dest.writeDouble(mSuccessfulTxPacketsPerSecond); dest.writeLong(txRetries); - dest.writeDouble(mTxRetriesRate); + dest.writeDouble(mTxRetriedTxPacketsPerSecond); dest.writeLong(txBad); - dest.writeDouble(mTxBadRate); + dest.writeDouble(mLostTxPacketsPerSecond); dest.writeLong(rxSuccess); - dest.writeDouble(mRxSuccessRate); + dest.writeDouble(mSuccessfulRxPacketsPerSecond); mSupplicantState.writeToParcel(dest, flags); dest.writeInt(mOsuAp ? 1 : 0); - dest.writeString(mAppPackageName); + dest.writeString(mRequestingPackageName); dest.writeString(mFqdn); dest.writeString(mProviderFriendlyName); dest.writeInt(mWifiStandard); @@ -1000,16 +1000,16 @@ public class WifiInfo implements Parcelable { info.mTrusted = in.readInt() != 0; info.score = in.readInt(); info.txSuccess = in.readLong(); - info.mTxSuccessRate = in.readDouble(); + info.mSuccessfulTxPacketsPerSecond = in.readDouble(); info.txRetries = in.readLong(); - info.mTxRetriesRate = in.readDouble(); + info.mTxRetriedTxPacketsPerSecond = in.readDouble(); info.txBad = in.readLong(); - info.mTxBadRate = in.readDouble(); + info.mLostTxPacketsPerSecond = in.readDouble(); info.rxSuccess = in.readLong(); - info.mRxSuccessRate = in.readDouble(); + info.mSuccessfulRxPacketsPerSecond = in.readDouble(); info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); info.mOsuAp = in.readInt() != 0; - info.mAppPackageName = in.readString(); + info.mRequestingPackageName = in.readString(); info.mFqdn = in.readString(); info.mProviderFriendlyName = in.readString(); info.mWifiStandard = in.readInt(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index fb3e794d92d1..c7475ee92dc7 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -4854,13 +4854,19 @@ public class WifiManager { /** * Set Wi-Fi verbose logging level from developer settings. * - * @param verbose the verbose logging level to set. 0 will disable verbose logging, a positive - * integer will enable verbose logging. + * @param enable true to enable verbose logging, false to disable. * * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + public void setVerboseLoggingEnabled(boolean enable) { + enableVerboseLogging(enable ? 1 : 0); + } + + /** @hide */ + @UnsupportedAppUsage + @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void enableVerboseLogging (int verbose) { try { mService.enableVerboseLogging(verbose); @@ -4871,15 +4877,23 @@ public class WifiManager { } /** - * Get the persisted WiFi verbose logging level, set by {@link #enableVerboseLogging(int)}. + * Get the persisted Wi-Fi verbose logging level, set by + * {@link #setVerboseLoggingEnabled(boolean)}. * No permissions are required to call this method. * - * @return 0 to indicate that verbose logging is disabled, a positive integer to indicate that - * verbose logging is enabled. + * @return true to indicate that verbose logging is enabled, false to indicate that verbose + * logging is disabled. * * @hide */ @SystemApi + public boolean isVerboseLoggingEnabled() { + return getVerboseLoggingLevel() > 0; + } + + /** @hide */ + // TODO(b/145484145): remove once SUW stops calling this via reflection + @UnsupportedAppUsage public int getVerboseLoggingLevel() { try { return mService.getVerboseLoggingLevel(); @@ -5204,7 +5218,7 @@ public class WifiManager { * level from wifi service. */ private void updateVerboseLoggingEnabledFromService() { - mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0; + mVerboseLoggingEnabled = isVerboseLoggingEnabled(); } /** diff --git a/wifi/tests/README.md b/wifi/tests/README.md index b0594f2d29b1..f90940470432 100644 --- a/wifi/tests/README.md +++ b/wifi/tests/README.md @@ -8,12 +8,9 @@ libraries. The easiest way to run tests is simply run ``` -frameworks/base/wifi/tests/runtests.sh +atest android.net.wifi ``` -`runtests.sh` will build the test project and all of its dependencies and push the APK to the -connected device. It will then run the tests on the device. - To pick up changes in framework/base, you will need to: 1. rebuild the framework library 'make -j32' 2. sync over the updated library to the device 'adb sync' @@ -24,22 +21,6 @@ To enable syncing data to the device for first time after clean reflash: 2. adb reboot 3. adb remount -See below for a few example of options to limit which tests are run. -See the -[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html) -for more details on the supported options. - -``` -runtests.sh -e package android.net.wifi -runtests.sh -e class android.net.wifi.WifiScannerTest -``` - -If you manually build and push the test APK to the device you can run tests using - -``` -adb shell am instrument -w 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner' -``` - ## Adding Tests Tests can be added by adding classes to the src directory. JUnit4 style test cases can be written by simply annotating test methods with `org.junit.Test`. diff --git a/wifi/tests/runtests.sh b/wifi/tests/runtests.sh deleted file mode 100755 index 4024371dd97d..000000000000 --- a/wifi/tests/runtests.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash - -if [ -z $ANDROID_BUILD_TOP ]; then - echo "You need to source and lunch before you can use this script" - exit 1 -fi - -echo "Running tests" - -set -e # fail early - -echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/base/wifi/tests" -# NOTE Don't actually run the command above since this shell doesn't inherit functions from the -# caller. -$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode MODULES-IN-frameworks-base-wifi-tests - -set -x # print commands - -adb wait-for-device - -TARGET_ARCH=$($ANDROID_BUILD_TOP/build/soong/soong_ui.bash --dumpvar-mode TARGET_ARCH) -adb install -r -g "$OUT/testcases/FrameworksWifiApiTests/$TARGET_ARCH/FrameworksWifiApiTests.apk" - -adb shell am instrument --no-hidden-api-checks -w "$@" \ - 'android.net.wifi.test/androidx.test.runner.AndroidJUnitRunner' diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java index 04759ac21bba..311bbc41b8fe 100644 --- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java +++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java @@ -64,7 +64,7 @@ public class WifiInfoTest { writeWifiInfo.setOsuAp(true); writeWifiInfo.setFQDN(TEST_FQDN); writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME); - writeWifiInfo.setAppPackageName(TEST_PACKAGE_NAME); + writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME); writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD); writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS); writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS); @@ -83,7 +83,7 @@ public class WifiInfoTest { assertTrue(readWifiInfo.isTrusted()); assertTrue(readWifiInfo.isOsuAp()); assertTrue(readWifiInfo.isPasspointAp()); - assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getAppPackageName()); + assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName()); assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn()); assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName()); assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard()); |