diff options
217 files changed, 8031 insertions, 1086 deletions
diff --git a/api/current.txt b/api/current.txt index eebe9a3c50c6..36a21c75c591 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10375,6 +10375,7 @@ package android.content { field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT"; field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON"; field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE"; + field public static final java.lang.String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID"; field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT"; field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME"; field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY"; @@ -11950,6 +11951,9 @@ package android.content.pm { method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent); method public android.content.pm.ShortcutInfo.Builder setIntents(android.content.Intent[]); method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.CharSequence); + method public android.content.pm.ShortcutInfo.Builder setLongLived(); + method public android.content.pm.ShortcutInfo.Builder setPerson(android.app.Person); + method public android.content.pm.ShortcutInfo.Builder setPersons(android.app.Person[]); method public android.content.pm.ShortcutInfo.Builder setRank(int); method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.CharSequence); } @@ -12290,6 +12294,7 @@ package android.content.res { method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException; method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics); + field public static final int ID_NULL = 0; // 0x0 } public static class Resources.NotFoundException extends java.lang.RuntimeException { @@ -24146,6 +24151,7 @@ package android.media { method public int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long); method protected void finalize(); method public void flush(); + method public java.lang.String getCanonicalName(); method public android.media.MediaCodecInfo getCodecInfo(); method public java.nio.ByteBuffer getInputBuffer(int); method public deprecated java.nio.ByteBuffer[] getInputBuffers(); @@ -24272,10 +24278,15 @@ package android.media { } public final class MediaCodecInfo { + method public java.lang.String getCanonicalName(); method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String); method public java.lang.String getName(); method public java.lang.String[] getSupportedTypes(); + method public boolean isAlias(); method public boolean isEncoder(); + method public boolean isHardwareAccelerated(); + method public boolean isSoftwareOnly(); + method public boolean isVendor(); } public static final class MediaCodecInfo.AudioCapabilities { @@ -24351,7 +24362,10 @@ package android.media { field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00 field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100 field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback"; + field public static final java.lang.String FEATURE_DynamicTimestamp = "dynamic-timestamp"; + field public static final java.lang.String FEATURE_FrameParsing = "frame-parsing"; field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh"; + field public static final java.lang.String FEATURE_MultipleFrames = "multiple-frames"; field public static final java.lang.String FEATURE_PartialFrame = "partial-frame"; field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback"; field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback"; @@ -24373,6 +24387,33 @@ package android.media { field public static final int AACObjectSSR = 3; // 0x3 field public static final int AACObjectScalable = 6; // 0x6 field public static final int AACObjectXHE = 42; // 0x2a + field public static final int AV1Level2 = 1; // 0x1 + field public static final int AV1Level21 = 2; // 0x2 + field public static final int AV1Level22 = 4; // 0x4 + field public static final int AV1Level23 = 8; // 0x8 + field public static final int AV1Level3 = 16; // 0x10 + field public static final int AV1Level31 = 32; // 0x20 + field public static final int AV1Level32 = 64; // 0x40 + field public static final int AV1Level33 = 128; // 0x80 + field public static final int AV1Level4 = 256; // 0x100 + field public static final int AV1Level41 = 512; // 0x200 + field public static final int AV1Level42 = 1024; // 0x400 + field public static final int AV1Level43 = 2048; // 0x800 + field public static final int AV1Level5 = 4096; // 0x1000 + field public static final int AV1Level51 = 8192; // 0x2000 + field public static final int AV1Level52 = 16384; // 0x4000 + field public static final int AV1Level53 = 32768; // 0x8000 + field public static final int AV1Level6 = 65536; // 0x10000 + field public static final int AV1Level61 = 131072; // 0x20000 + field public static final int AV1Level62 = 262144; // 0x40000 + field public static final int AV1Level63 = 524288; // 0x80000 + field public static final int AV1Level7 = 1048576; // 0x100000 + field public static final int AV1Level71 = 2097152; // 0x200000 + field public static final int AV1Level72 = 4194304; // 0x400000 + field public static final int AV1Level73 = 8388608; // 0x800000 + field public static final int AV1Profile0 = 1; // 0x1 + field public static final int AV1Profile1 = 2; // 0x2 + field public static final int AV1Profile2 = 4; // 0x4 field public static final int AVCLevel1 = 1; // 0x1 field public static final int AVCLevel11 = 4; // 0x4 field public static final int AVCLevel12 = 8; // 0x8 @@ -24390,6 +24431,9 @@ package android.media { field public static final int AVCLevel5 = 16384; // 0x4000 field public static final int AVCLevel51 = 32768; // 0x8000 field public static final int AVCLevel52 = 65536; // 0x10000 + field public static final int AVCLevel6 = 131072; // 0x20000 + field public static final int AVCLevel61 = 262144; // 0x40000 + field public static final int AVCLevel62 = 524288; // 0x80000 field public static final int AVCProfileBaseline = 1; // 0x1 field public static final int AVCProfileConstrainedBaseline = 65536; // 0x10000 field public static final int AVCProfileConstrainedHigh = 524288; // 0x80000 @@ -24552,12 +24596,53 @@ package android.media { method public android.util.Range<java.lang.Double> getSupportedFrameRatesFor(int, int); method public android.util.Range<java.lang.Integer> getSupportedHeights(); method public android.util.Range<java.lang.Integer> getSupportedHeightsFor(int); + method public java.util.List<android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint> getSupportedPerformancePoints(); method public android.util.Range<java.lang.Integer> getSupportedWidths(); method public android.util.Range<java.lang.Integer> getSupportedWidthsFor(int); method public int getWidthAlignment(); method public boolean isSizeSupported(int, int); } + public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint { + method public boolean covers(android.media.MediaFormat); + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50; + field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60; + field public final int frameRate; + field public final int height; + field public final int width; + } + public final class MediaCodecList { ctor public MediaCodecList(int); method public java.lang.String findDecoderForFormat(android.media.MediaFormat); @@ -24574,6 +24659,7 @@ package android.media { ctor public MediaController2(android.content.Context, android.media.Session2Token, java.util.concurrent.Executor, android.media.MediaController2.ControllerCallback); method public void cancelSessionCommand(java.lang.Object); method public void close(); + method public boolean isPlaybackActive(); method public java.lang.Object sendSessionCommand(android.media.Session2Command, android.os.Bundle); } @@ -24582,6 +24668,7 @@ package android.media { method public void onCommandResult(android.media.MediaController2, java.lang.Object, android.media.Session2Command, android.media.Session2Command.Result); method public void onConnected(android.media.MediaController2, android.media.Session2CommandGroup); method public void onDisconnected(android.media.MediaController2); + method public void onPlaybackActiveChanged(android.media.MediaController2, boolean); method public android.media.Session2Command.Result onSessionCommand(android.media.MediaController2, android.media.Session2Command, android.os.Bundle); } @@ -25010,6 +25097,7 @@ package android.media { field public static final java.lang.String MIMETYPE_TEXT_CEA_708 = "text/cea-708"; field public static final java.lang.String MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; field public static final java.lang.String MIMETYPE_TEXT_VTT = "text/vtt"; + field public static final java.lang.String MIMETYPE_VIDEO_AV1 = "video/av01"; field public static final java.lang.String MIMETYPE_VIDEO_AVC = "video/avc"; field public static final java.lang.String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision"; field public static final java.lang.String MIMETYPE_VIDEO_H263 = "video/3gpp"; @@ -25923,7 +26011,9 @@ package android.media { method public void close(); method public java.lang.String getSessionId(); method public android.media.Session2Token getSessionToken(); + method public boolean isPlaybackActive(); method public java.lang.Object sendSessionCommand(android.media.MediaSession2.ControllerInfo, android.media.Session2Command, android.os.Bundle); + method public void setPlaybackActive(boolean); } public static final class MediaSession2.Builder { @@ -29831,7 +29921,7 @@ package android.net.wifi { method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); method public int getMaxNumberOfNetworkSuggestionsPerApp(); - method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations(); + method public deprecated java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); method public int getWifiState(); method public boolean is5GHzBandSupported(); @@ -29851,7 +29941,7 @@ package android.net.wifi { method public deprecated boolean reconnect(); method public deprecated boolean removeNetwork(int); method public int removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>); - method public void removePasspointConfiguration(java.lang.String); + method public deprecated void removePasspointConfiguration(java.lang.String); method public deprecated boolean saveConfiguration(); method public void setTdlsEnabled(java.net.InetAddress, boolean); method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean); @@ -52589,6 +52679,7 @@ package android.view.contentcapture { method public final void notifyViewAppeared(android.view.ViewStructure); method public final void notifyViewDisappeared(android.view.autofill.AutofillId); method public final void notifyViewTextChanged(android.view.autofill.AutofillId, java.lang.CharSequence, int); + method public final void notifyViewsDisappeared(android.view.autofill.AutofillId, int[]); field public static final int FLAG_USER_INPUT = 1; // 0x1 } diff --git a/api/system-current.txt b/api/system-current.txt index 7ea7afbb8d20..5b153f04945b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -197,6 +197,7 @@ package android { } public static final class R.array { + field public static final int config_defaultRoleHolders = 17235974; // 0x1070006 field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005 } @@ -1570,6 +1571,18 @@ package android.content.pm { field public int requestRes; } + public class ShortcutManager { + method public java.util.List<android.content.pm.ShortcutManager.ShareShortcutInfo> getShareTargets(android.content.IntentFilter); + } + + public static final class ShortcutManager.ShareShortcutInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.content.pm.ShortcutInfo getShortcutInfo(); + method public android.content.ComponentName getTargetComponent(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutManager.ShareShortcutInfo> CREATOR; + } + public final class SuspendDialogInfo implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); @@ -4143,12 +4156,19 @@ package android.net.wifi { field public static final int WPA2_PSK = 4; // 0x4 } + public class WifiInfo implements android.os.Parcelable { + method public boolean isOsuAp(); + } + public class WifiManager { method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener); method public void connect(int, android.net.wifi.WifiManager.ActionListener); method public void disable(int, android.net.wifi.WifiManager.ActionListener); method public void disableEphemeralNetwork(java.lang.String); method public void forget(int, android.net.wifi.WifiManager.ActionListener); + method 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(java.util.List<android.net.wifi.ScanResult>); + method public java.util.Map<android.net.wifi.hotspot2.OsuProvider, java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>); + method public java.util.Map<android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(java.util.Set<android.net.wifi.hotspot2.OsuProvider>); method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks(); method public android.net.wifi.WifiConfiguration getWifiApConfiguration(); method public int getWifiApState(); @@ -4163,6 +4183,7 @@ package android.net.wifi { method public void startEasyConnectAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.EasyConnectStatusCallback); method public void startEasyConnectAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.EasyConnectStatusCallback); method public boolean startScan(android.os.WorkSource); + method public void startSubscriptionProvisioning(android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.ProvisioningCallback, android.os.Handler); method public void stopEasyConnectSession(); method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback); field public static final int CHANGE_REASON_ADDED = 0; // 0x0 @@ -4182,6 +4203,8 @@ package android.net.wifi { field public static final java.lang.String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration"; field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et"; field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_SSID = "ssid"; + field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0 + field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1 field public static final java.lang.String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED"; field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa @@ -4358,6 +4381,59 @@ package android.net.wifi.aware { } +package android.net.wifi.hotspot2 { + + public final class OsuProvider implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getFriendlyName(); + method public android.net.Uri getServerUri(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR; + } + + public abstract class ProvisioningCallback { + ctor public ProvisioningCallback(); + method public abstract void onProvisioningComplete(); + method public abstract void onProvisioningFailure(int); + method public abstract void onProvisioningStatus(int); + field public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; // 0x16 + field public static final int OSU_FAILURE_AP_CONNECTION = 1; // 0x1 + field public static final int OSU_FAILURE_INVALID_SERVER_URL = 8; // 0x8 + field public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; // 0x11 + field public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; // 0x15 + field public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14; // 0xe + field public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; // 0x13 + field public static final int OSU_FAILURE_NO_PPS_MO = 16; // 0x10 + field public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; // 0x12 + field public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23; // 0x17 + field public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; // 0x6 + field public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; // 0x7 + field public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; // 0x14 + field public static final int OSU_FAILURE_SERVER_CONNECTION = 3; // 0x3 + field public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; // 0x2 + field public static final int OSU_FAILURE_SERVER_VALIDATION = 4; // 0x4 + field public static final int OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5; // 0x5 + field public static final int OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11; // 0xb + field public static final int OSU_FAILURE_START_REDIRECT_LISTENER = 12; // 0xc + field public static final int OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13; // 0xd + field public static final int OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9; // 0x9 + field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; // 0xf + field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10; // 0xa + field public static final int OSU_STATUS_AP_CONNECTED = 2; // 0x2 + field public static final int OSU_STATUS_AP_CONNECTING = 1; // 0x1 + field public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6; // 0x6 + field public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8; // 0x8 + field public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; // 0xb + field public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9; // 0x9 + field public static final int OSU_STATUS_SERVER_CONNECTED = 5; // 0x5 + field public static final int OSU_STATUS_SERVER_CONNECTING = 3; // 0x3 + field public static final int OSU_STATUS_SERVER_VALIDATED = 4; // 0x4 + field public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; // 0xa + field public static final int OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE = 7; // 0x7 + } + +} + package android.net.wifi.rtt { public static final class RangingRequest.Builder { @@ -5028,6 +5104,7 @@ package android.provider { method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener); method public static void resetToDefaults(int, java.lang.String); method public static boolean setProperty(java.lang.String, java.lang.String, java.lang.String, boolean); + field public static final java.lang.String NAMESPACE_GAME_DRIVER = "game_driver"; field public static final java.lang.String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot"; } @@ -6270,6 +6347,30 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string"; } + public final class CarrierRestrictionRules implements android.os.Parcelable { + method public int describeContents(); + method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(); + method public int getDefaultCarrierRestriction(); + method public java.util.List<android.service.carrier.CarrierIdentifier> getExcludedCarriers(); + method public int getMultiSimPolicy(); + method public boolean isAllCarriersAllowed(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; // 0x1 + field public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; // 0x0 + field public static final android.os.Parcelable.Creator<android.telephony.CarrierRestrictionRules> CREATOR; + field public static final int MULTISIM_POLICY_NONE = 0; // 0x0 + field public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; // 0x1 + } + + public static class CarrierRestrictionRules.Builder { + method public android.telephony.CarrierRestrictionRules build(); + method public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed(); + method public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>); + method public android.telephony.CarrierRestrictionRules.Builder setDefaultCarrierRestriction(int); + method public android.telephony.CarrierRestrictionRules.Builder setExcludedCarriers(java.util.List<android.service.carrier.CarrierIdentifier>); + method public android.telephony.CarrierRestrictionRules.Builder setMultiSimPolicy(int); + } + public final class DataFailCause { field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f @@ -6765,10 +6866,11 @@ package android.telephony { method public boolean enableDataConnectivity(); method public void enableVideoCalling(boolean); method public java.lang.String getAidForAppType(int); - method public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); + method public deprecated java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); method public int getCardIdForDefaultEuicc(); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); + method public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method public java.lang.String getCdmaMdn(); method public java.lang.String getCdmaMdn(int); method public java.lang.String getCdmaMin(); @@ -6807,8 +6909,9 @@ package android.telephony { method public void requestCellInfoUpdate(android.os.WorkSource, java.util.concurrent.Executor, android.telephony.TelephonyManager.CellInfoCallback); method public void requestNumberVerification(android.telephony.PhoneNumberRange, long, java.util.concurrent.Executor, android.telephony.NumberVerificationCallback); method public boolean resetRadioConfig(); - method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); + method public deprecated int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method public void setCarrierDataEnabled(boolean); + method public int setCarrierRestrictionRules(android.telephony.CarrierRestrictionRules); method public void setDataActivationState(int); method public deprecated void setDataEnabled(int, boolean); method public void setDataRoamingEnabled(boolean); @@ -6860,6 +6963,9 @@ package android.telephony { field public static final int RADIO_POWER_OFF = 0; // 0x0 field public static final int RADIO_POWER_ON = 1; // 0x1 field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2 + field public static final int SET_CARRIER_RESTRICTION_ERROR = 2; // 0x2 + field public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; // 0x1 + field public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0; // 0x0 field public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2; // 0x2 field public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1; // 0x1 field public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3; // 0x3 @@ -7190,6 +7296,7 @@ package android.telephony.ims { method public int getServiceType(); method public static int getVideoStateFromCallType(int); method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile); + method public boolean isEmergencyCallTesting(); method public boolean isVideoCall(); method public boolean isVideoPaused(); method public static int presentationToOir(int); @@ -7198,6 +7305,7 @@ package android.telephony.ims { method public void setCallExtraInt(java.lang.String, int); method public void setCallRestrictCause(int); method public void setEmergencyCallRouting(int); + method public void setEmergencyCallTesting(boolean); method public void setEmergencyServiceCategories(int); method public void setEmergencyUrns(java.util.List<java.lang.String>); method public void updateCallExtras(android.telephony.ims.ImsCallProfile); diff --git a/api/test-current.txt b/api/test-current.txt index 846442dbe031..e0e0f3506ad4 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -580,6 +580,8 @@ package android.hardware.display { public final class BrightnessConfiguration implements android.os.Parcelable { method public int describeContents(); + method public android.hardware.display.BrightnessCorrection getCorrectionByCategory(int); + method public android.hardware.display.BrightnessCorrection getCorrectionByPackageName(java.lang.String); method public android.util.Pair<float[], float[]> getCurve(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR; @@ -587,10 +589,22 @@ package android.hardware.display { public static class BrightnessConfiguration.Builder { ctor public BrightnessConfiguration.Builder(float[], float[]); + method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByCategory(int, android.hardware.display.BrightnessCorrection); + method public android.hardware.display.BrightnessConfiguration.Builder addCorrectionByPackageName(java.lang.String, android.hardware.display.BrightnessCorrection); method public android.hardware.display.BrightnessConfiguration build(); + method public int getMaxCorrectionsByCategory(); + method public int getMaxCorrectionsByPackageName(); method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String); } + public final class BrightnessCorrection implements android.os.Parcelable { + method public float apply(float); + method public static android.hardware.display.BrightnessCorrection createScaleAndTranslateLog(float, float); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessCorrection> CREATOR; + } + public final class DisplayManager { method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats(); method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration(); @@ -1104,6 +1118,24 @@ package android.os { field public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Waveform> CREATOR; } + public class VintfObject { + method public static java.lang.String[] getHalNamesAndVersions(); + method public static java.lang.String getSepolicyVersion(); + method public static java.lang.Long getTargetFrameworkCompatibilityMatrixVersion(); + method public static java.util.Map<java.lang.String, java.lang.String[]> getVndkSnapshots(); + method public static java.lang.String[] report(); + } + + public class VintfRuntimeInfo { + method public static java.lang.String getCpuInfo(); + method public static java.lang.String getHardwareId(); + method public static java.lang.String getKernelVersion(); + method public static java.lang.String getNodeName(); + method public static java.lang.String getOsName(); + method public static java.lang.String getOsRelease(); + method public static java.lang.String getOsVersion(); + } + public class WorkSource implements android.os.Parcelable { ctor public WorkSource(int); method public boolean add(int); diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index abe18ba8a415..803f83c0bc6f 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -20,6 +20,7 @@ cc_defaults { "misc-*", "modernize-*", "readability-*", + "-modernize-avoid-c-arrays", ], tidy_flags: [ "-system-headers", @@ -38,6 +39,7 @@ cc_library { "libidmap2/CommandLineOptions.cpp", "libidmap2/FileUtils.cpp", "libidmap2/Idmap.cpp", + "libidmap2/Policies.cpp", "libidmap2/PrettyPrintVisitor.cpp", "libidmap2/RawPrintVisitor.cpp", "libidmap2/ResourceUtils.cpp", @@ -87,6 +89,7 @@ cc_test { "tests/Idmap2BinaryTests.cpp", "tests/IdmapTests.cpp", "tests/Main.cpp", + "tests/PoliciesTests.cpp", "tests/PrettyPrintVisitorTests.cpp", "tests/RawPrintVisitorTests.cpp", "tests/ResourceUtilsTests.cpp", diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp index b07567331e85..c455ac0f83af 100644 --- a/cmds/idmap2/idmap2/Create.cpp +++ b/cmds/idmap2/idmap2/Create.cpp @@ -27,17 +27,25 @@ #include "idmap2/CommandLineOptions.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" +#include "idmap2/Policies.h" +#include "idmap2/Result.h" using android::ApkAssets; using android::idmap2::BinaryStreamVisitor; using android::idmap2::CommandLineOptions; using android::idmap2::Idmap; +using android::idmap2::PoliciesToBitmask; +using android::idmap2::PolicyBitmask; +using android::idmap2::PolicyFlags; +using android::idmap2::Result; using android::idmap2::utils::kIdmapFilePermissionMask; bool Create(const std::vector<std::string>& args, std::ostream& out_error) { std::string target_apk_path; std::string overlay_apk_path; std::string idmap_path; + std::vector<std::string> policies; + bool ignore_overlayable; const CommandLineOptions opts = CommandLineOptions("idmap2 create") @@ -47,12 +55,28 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) { .MandatoryOption("--overlay-apk-path", "input: path to apk which contains the new resource values", &overlay_apk_path) - .MandatoryOption("--idmap-path", "output: path to where to write idmap file", - &idmap_path); + .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path) + .OptionalOption("--policy", + "input: an overlayable policy this overlay fulfills " + "(if none or supplied, the overlay policy will default to \"public\")", + &policies) + .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks", + &ignore_overlayable); if (!opts.Parse(args, out_error)) { return false; } + PolicyBitmask fulfilled_policies = 0; + if (auto result = PoliciesToBitmask(policies, out_error)) { + fulfilled_policies |= *result; + } else { + return false; + } + + if (fulfilled_policies == 0) { + fulfilled_policies |= PolicyFlags::POLICY_PUBLIC; + } + const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); if (!target_apk) { out_error << "error: failed to load apk " << target_apk_path << std::endl; @@ -66,7 +90,8 @@ bool Create(const std::vector<std::string>& args, std::ostream& out_error) { } const std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + fulfilled_policies, !ignore_overlayable, out_error); if (!idmap) { return false; } diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index 4f88127f8af1..a269ee958497 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -21,8 +21,11 @@ #include <set> #include <sstream> #include <string> +#include <utility> #include <vector> +#include "android-base/properties.h" + #include "idmap2/CommandLineOptions.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" @@ -34,6 +37,10 @@ using android::idmap2::CommandLineOptions; using android::idmap2::Idmap; using android::idmap2::MemoryChunk; +using android::idmap2::PoliciesToBitmask; +using android::idmap2::PolicyBitmask; +using android::idmap2::PolicyFlags; +using android::idmap2::Result; using android::idmap2::Xml; using android::idmap2::ZipFile; using android::idmap2::utils::FindFiles; @@ -45,11 +52,19 @@ struct InputOverlay { return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path); } - std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes) - std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes) - int priority; // NOLINT(misc-non-private-member-variables-in-classes) + std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes) + std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes) + int priority; // NOLINT(misc-non-private-member-variables-in-classes) + std::vector<std::string> policies; // NOLINT(misc-non-private-member-variables-in-classes) + bool ignore_overlayable; // NOLINT(misc-non-private-member-variables-in-classes) }; +bool VendorIsQOrLater() { + // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized + std::string version = android::base::GetProperty("ro.vndk.version", "Q"); + return version == "Q" || version == "q"; +} + std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs, bool recursive, std::ostream& out_error) { const auto predicate = [](unsigned char type, const std::string& path) -> bool { @@ -70,6 +85,22 @@ std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::st return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend()); } +PolicyBitmask PolicyForPath(const std::string& apk_path) { + static const std::vector<std::pair<std::string, PolicyBitmask>> values = { + {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION}, + {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION}, + {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION}, + }; + + for (auto const& pair : values) { + if (apk_path.compare(0, pair.first.size(), pair.first) == 0) { + return pair.second | PolicyFlags::POLICY_PUBLIC; + } + } + + return PolicyFlags::POLICY_PUBLIC; +} + } // namespace bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { @@ -77,6 +108,7 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { std::string target_package_name; std::string target_apk_path; std::string output_directory; + std::vector<std::string> override_policies; bool recursive = false; const CommandLineOptions opts = @@ -89,7 +121,12 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path) .MandatoryOption("--output-directory", "directory in which to write artifacts (idmap files and overlays.list)", - &output_directory); + &output_directory) + .OptionalOption( + "--override-policy", + "input: an overlayable policy this overlay fulfills " + "(if none or supplied, the overlays will not have their policies overriden", + &override_policies); if (!opts.Parse(args, out_error)) { return false; } @@ -144,29 +181,63 @@ bool Scan(const std::vector<std::string>& args, std::ostream& out_error) { continue; } - // Sort the static overlays in ascending priority order + PolicyBitmask fulfilled_policies; + if (!override_policies.empty()) { + if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) { + fulfilled_policies = *result; + } else { + return false; + } + } else { + fulfilled_policies = PolicyForPath(path); + } + + bool ignore_overlayable = false; + if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) { + // If the overlay is on a pre-Q vendor partition, do not enforce overlayable + // restrictions on this overlay because the pre-Q platform has no understanding of + // overlayable. + ignore_overlayable = true; + } + std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path); - InputOverlay input{path, idmap_path, priority}; + + // Sort the static overlays in ascending priority order + InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable}; interesting_apks.insert( std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input); } std::stringstream stream; for (const auto& overlay : interesting_apks) { + // Create the idmap for the overlay if it currently does not exist or if it is not up to date. std::stringstream dev_null; - if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) && - !Create(std::vector<std::string>({ - "--target-apk-path", - target_apk_path, - "--overlay-apk-path", - overlay.apk_path, - "--idmap-path", - overlay.idmap_path, - }), - out_error)) { - return false; + + std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path}; + for (const std::string& policy : overlay.policies) { + verify_args.emplace_back("--policy"); + verify_args.emplace_back(policy); } - stream << overlay.idmap_path << std::endl; + + if (!Verify(std::vector<std::string>(verify_args), dev_null)) { + std::vector<std::string> create_args = {"--target-apk-path", target_apk_path, + "--overlay-apk-path", overlay.apk_path, + "--idmap-path", overlay.idmap_path}; + if (overlay.ignore_overlayable) { + create_args.emplace_back("--ignore-overlayable"); + } + + for (const std::string& policy : overlay.policies) { + verify_args.emplace_back("--policy"); + verify_args.emplace_back(policy); + } + + if (!Create(create_args, out_error)) { + return false; + } + } + + stream << overlay.idmap_path << std::endl; } std::cout << stream.str(); diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index d2e46e15fc59..a3c752718ee2 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -26,12 +26,15 @@ #include <string> #include "android-base/macros.h" +#include "android-base/stringprintf.h" #include "utils/String8.h" #include "utils/Trace.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" +#include "idmap2/Policies.h" +#include "idmap2/Result.h" #include "idmap2d/Idmap2Service.h" @@ -39,6 +42,8 @@ using android::binder::Status; using android::idmap2::BinaryStreamVisitor; using android::idmap2::Idmap; using android::idmap2::IdmapHeader; +using android::idmap2::PolicyBitmask; +using android::idmap2::Result; using android::idmap2::utils::kIdmapFilePermissionMask; namespace { @@ -54,6 +59,10 @@ Status error(const std::string& msg) { return Status::fromExceptionCode(Status::EX_NONE, msg.c_str()); } +PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) { + return static_cast<PolicyBitmask>(arg); +} + } // namespace namespace android::os { @@ -78,6 +87,8 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path, } Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path, + int32_t fulfilled_policies ATTRIBUTE_UNUSED, + bool enforce_overlayable ATTRIBUTE_UNUSED, int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) { assert(_aidl_return); const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); @@ -86,11 +97,15 @@ Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path, fin.close(); std::stringstream dev_null; *_aidl_return = header && header->IsUpToDate(dev_null); + + // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed + return ok(); } Status Idmap2Service::createIdmap(const std::string& target_apk_path, - const std::string& overlay_apk_path, int32_t user_id, + const std::string& overlay_apk_path, int32_t fulfilled_policies, + bool enforce_overlayable, int32_t user_id, std::unique_ptr<std::string>* _aidl_return) { assert(_aidl_return); std::stringstream trace; @@ -101,6 +116,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path, _aidl_return->reset(nullptr); + const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies); + const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); if (!target_apk) { return error("failed to load apk " + target_apk_path); @@ -113,7 +130,8 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path, std::stringstream err; const std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + policy_bitmask, enforce_overlayable, err); if (!idmap) { return error(err.str()); } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h index e0bc22e9e9e6..1aab0598449b 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.h +++ b/cmds/idmap2/idmap2d/Idmap2Service.h @@ -39,11 +39,12 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 { binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id, bool* _aidl_return); - binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id, - bool* _aidl_return); + binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies, + bool enforce_overlayable, int32_t user_id, bool* _aidl_return); binder::Status createIdmap(const std::string& target_apk_path, - const std::string& overlay_apk_path, int32_t user_id, + const std::string& overlay_apk_path, int32_t fulfilled_policies, + bool enforce_overlayable, int32_t user_id, std::unique_ptr<std::string>* _aidl_return); }; diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl index d475417a0935..ea7274f3ea58 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl @@ -20,9 +20,18 @@ package android.os; * @hide */ interface IIdmap2 { + const int POLICY_PUBLIC = 0x00000001; + const int POLICY_SYSTEM_PARTITION = 0x00000002; + const int POLICY_VENDOR_PARTITION = 0x00000004; + const int POLICY_PRODUCT_PARTITION = 0x00000008; + @utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId); boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId); - boolean verifyIdmap(@utf8InCpp String overlayApkPath, int userId); + boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies, + boolean enforceOverlayable, int userId); @nullable @utf8InCpp String createIdmap(@utf8InCpp String targetApkPath, - @utf8InCpp String overlayApkPath, int userId); + @utf8InCpp String overlayApkPath, + int fulfilledPolicies, + boolean enforceOverlayable, + int userId); } diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h index b93e71631d08..6db6bf9ea8ad 100644 --- a/cmds/idmap2/include/idmap2/CommandLineOptions.h +++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h @@ -44,6 +44,8 @@ class CommandLineOptions { std::vector<std::string>* value); CommandLineOptions& OptionalOption(const std::string& name, const std::string& description, std::string* value); + CommandLineOptions& OptionalOption(const std::string& name, const std::string& description, + std::vector<std::string>* value); bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const; void Usage(std::ostream& out) const; @@ -56,6 +58,7 @@ class CommandLineOptions { COUNT_OPTIONAL, COUNT_EXACTLY_ONCE, COUNT_ONCE_OR_MORE, + COUNT_OPTIONAL_ONCE_OR_MORE, } count; bool argument; }; diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index b989e4c3f9d1..1666dc8a3bbd 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -57,6 +57,8 @@ #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" +#include "idmap2/Policies.h" + namespace android::idmap2 { class Idmap; @@ -233,11 +235,10 @@ class Idmap { // file is used; change this in the next version of idmap to use a named // package instead; also update FromApkAssets to take additional parameters: // the target and overlay package names - static std::unique_ptr<const Idmap> FromApkAssets(const std::string& target_apk_path, - const ApkAssets& target_apk_assets, - const std::string& overlay_apk_path, - const ApkAssets& overlay_apk_assets, - std::ostream& out_error); + static std::unique_ptr<const Idmap> FromApkAssets( + const std::string& target_apk_path, const ApkAssets& target_apk_assets, + const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets, + const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error); inline const std::unique_ptr<const IdmapHeader>& GetHeader() const { return header_; diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h new file mode 100644 index 000000000000..eecee25445e2 --- /dev/null +++ b/cmds/idmap2/include/idmap2/Policies.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ostream> +#include <string> +#include <vector> + +#include "androidfw/ResourceTypes.h" +#include "androidfw/StringPiece.h" + +#include "Result.h" + +#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ +#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ + +namespace android::idmap2 { + +using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags; +using PolicyBitmask = uint32_t; + +// Parses a the string representation of a set of policies into a bitmask. The format of the string +// is the same as for the <policy> element. +Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies, + std::ostream& err); + +} // namespace android::idmap2 + +#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp index cabc8f398c46..a49a607091a4 100644 --- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp +++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp @@ -68,9 +68,18 @@ CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name, return *this; } +CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name, + const std::string& description, + std::vector<std::string>* value) { + assert(value != nullptr); + auto func = [value](const std::string& arg) -> void { value->push_back(arg); }; + options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL_ONCE_OR_MORE, true}); + return *this; +} + bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const { const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) { - return opt.count != Option::COUNT_OPTIONAL; + return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE; }); std::set<std::string> mandatory_opts; std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()), @@ -122,7 +131,8 @@ void CommandLineOptions::Usage(std::ostream& out) const { size_t maxLength = 0; out << "usage: " << name_; for (const Option& opt : options_) { - const bool mandatory = opt.count != Option::COUNT_OPTIONAL; + const bool mandatory = + opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE; out << " "; if (!mandatory) { out << "["; @@ -134,9 +144,15 @@ void CommandLineOptions::Usage(std::ostream& out) const { out << opt.name; maxLength = std::max(maxLength, opt.name.size()); } + + if (opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) { + out << " [..]"; + } + if (!mandatory) { out << "]"; } + if (opt.count == Option::COUNT_ONCE_OR_MORE) { out << " [" << opt.name << " arg [..]]"; } @@ -150,7 +166,8 @@ void CommandLineOptions::Usage(std::ostream& out) const { out << opt.name; } out << " " << opt.description; - if (opt.count == Option::COUNT_ONCE_OR_MORE) { + if (opt.count == Option::COUNT_ONCE_OR_MORE || + opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) { out << " (can be provided multiple times)"; } out << std::endl; diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 37d6af8fa477..2890ae11b0af 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -274,11 +274,23 @@ std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream, return std::move(idmap); } -std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_path, - const ApkAssets& target_apk_assets, - const std::string& overlay_apk_path, - const ApkAssets& overlay_apk_assets, - std::ostream& out_error) { +bool CheckOverlayable(const LoadedPackage& target_package, PolicyBitmask fulfilled_polices, + ResourceId resid) { + const OverlayableInfo* info = target_package.GetOverlayableInfo(resid); + if (info == nullptr) { + // If the resource does not have an overlayable definition, allow the resource to be overlaid. + // Once overlayable enforcement is turned on, this check will return false. + return true; + } + + // Enforce policy restrictions if the resource is declared as overlayable. + return (info->policy_flags & fulfilled_polices) != 0; +} + +std::unique_ptr<const Idmap> Idmap::FromApkAssets( + const std::string& target_apk_path, const ApkAssets& target_apk_assets, + const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets, + const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) { AssetManager2 target_asset_manager; if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) { out_error << "error: failed to create target asset manager" << std::endl; @@ -380,6 +392,15 @@ std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_ if (target_resid == 0) { continue; } + + if (enforce_overlayable && !CheckOverlayable(*target_pkg, fulfilled_policies, target_resid)) { + // The resources must be defined as overlayable and the overlay must fulfill at least one + // policy enforced on the overlayable resource + LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \"" + << full_name << "\"" << std::endl; + continue; + } + matching_resources.Add(target_resid, overlay_resid); } diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp new file mode 100644 index 000000000000..0f87ef0c4ea9 --- /dev/null +++ b/cmds/idmap2/libidmap2/Policies.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <iterator> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include "androidfw/ResourceTypes.h" + +#include "idmap2/Idmap.h" +#include "idmap2/Policies.h" +#include "idmap2/Result.h" + +namespace android::idmap2 { + +namespace { + +const std::map<android::StringPiece, PolicyFlags> kStringToFlag = { + {"public", PolicyFlags::POLICY_PUBLIC}, + {"product", PolicyFlags::POLICY_PRODUCT_PARTITION}, + {"system", PolicyFlags::POLICY_SYSTEM_PARTITION}, + {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION}, +}; +} // namespace + +Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies, + std::ostream& err) { + PolicyBitmask bitmask = 0; + for (const std::string& policy : policies) { + const auto iter = kStringToFlag.find(policy); + if (iter != kStringToFlag.end()) { + bitmask |= iter->second; + } else { + err << "error: unknown policy \"" << policy << "\""; + return kResultError; + } + } + + return Result<PolicyBitmask>(bitmask); +} + +} // namespace android::idmap2 diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp index 2698ac0a734d..35ec1ff1dbb5 100644 --- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp +++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp @@ -78,7 +78,8 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) { std::stringstream error; std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error); ASSERT_THAT(idmap, NotNull()); std::stringstream stream; @@ -101,25 +102,52 @@ TEST(BinaryStreamVisitorTests, CreateIdmapFromApkAssetsInteropWithLoadedIdmap) { header = loaded_idmap->GetEntryMapForType(0x02); ASSERT_THAT(header, NotNull()); - success = LoadedIdmap::Lookup(header, 0x0002, &entry); + success = LoadedIdmap::Lookup(header, 0x0000, &entry); // string/a ASSERT_FALSE(success); - success = LoadedIdmap::Lookup(header, 0x0003, &entry); + success = LoadedIdmap::Lookup(header, 0x0001, &entry); // string/b + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0002, &entry); // string/c + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0003, &entry); // string/not_overlayable + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0004, &entry); // string/policy_product + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0005, &entry); // string/policy_public + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0006, &entry); // string/policy_system + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0007, &entry); // string/policy_system_vendor + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x0008, &entry); // string/str1 ASSERT_TRUE(success); ASSERT_EQ(entry, 0x0000); - success = LoadedIdmap::Lookup(header, 0x0004, &entry); + success = LoadedIdmap::Lookup(header, 0x0009, &entry); // string/str2 ASSERT_FALSE(success); - success = LoadedIdmap::Lookup(header, 0x0005, &entry); + success = LoadedIdmap::Lookup(header, 0x000a, &entry); // string/str3 ASSERT_TRUE(success); ASSERT_EQ(entry, 0x0001); - success = LoadedIdmap::Lookup(header, 0x0006, &entry); + success = LoadedIdmap::Lookup(header, 0x000b, &entry); // string/str4 ASSERT_TRUE(success); ASSERT_EQ(entry, 0x0002); - success = LoadedIdmap::Lookup(header, 0x0007, &entry); + success = LoadedIdmap::Lookup(header, 0x000c, &entry); // string/x + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x000d, &entry); // string/y + ASSERT_FALSE(success); + + success = LoadedIdmap::Lookup(header, 0x000e, &entry); // string/z ASSERT_FALSE(success); } diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp index c27d27a16b94..39f18d3336af 100644 --- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp +++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp @@ -121,6 +121,56 @@ TEST(CommandLineOptionsTests, OptionalOption) { ASSERT_FALSE(success); } +TEST(CommandLineOptionsTests, OptionalOptionList) { + std::vector<std::string> foo; + std::vector<std::string> bar; + CommandLineOptions opts = CommandLineOptions("test") + .OptionalOption("--foo", "", &foo) + .OptionalOption("--bar", "", &bar); + std::ostream fakeStdErr(nullptr); + bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr); + ASSERT_TRUE(success); + ASSERT_EQ(foo.size(), 1U); + ASSERT_EQ(foo[0], "FOO"); + ASSERT_EQ(bar.size(), 1U); + ASSERT_EQ(bar[0], "BAR"); + + foo.clear(); + bar.clear(); + success = opts.Parse({"--foo", "BAZ"}, fakeStdErr); + ASSERT_TRUE(success); + ASSERT_EQ(foo.size(), 1U); + ASSERT_EQ(foo[0], "BAZ"); + ASSERT_EQ(bar.size(), 0U); + + foo.clear(); + bar.clear(); + success = + opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr); + ASSERT_TRUE(success); + ASSERT_EQ(foo.size(), 2U); + ASSERT_EQ(foo[0], "BAZ"); + ASSERT_EQ(foo[1], "BIZ"); + ASSERT_EQ(bar.size(), 2U); + ASSERT_EQ(bar[0], "FIZ"); + ASSERT_EQ(bar[1], "FUZZ"); + + foo.clear(); + bar.clear(); + success = opts.Parse({"--foo"}, fakeStdErr); + ASSERT_FALSE(success); + + foo.clear(); + bar.clear(); + success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr); + ASSERT_FALSE(success); + + foo.clear(); + bar.clear(); + success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr); + ASSERT_FALSE(success); +} + TEST(CommandLineOptionsTests, CornerCases) { std::string foo; std::string bar; @@ -172,6 +222,7 @@ TEST(CommandLineOptionsTests, Usage) { bool arg5 = false; bool arg6 = false; std::vector<std::string> arg7; + std::vector<std::string> arg8; CommandLineOptions opts = CommandLineOptions("test") .MandatoryOption("--aa", "description-aa", &arg1) .OptionalFlag("--bb", "description-bb", &arg5) @@ -179,12 +230,13 @@ TEST(CommandLineOptionsTests, Usage) { .OptionalOption("--dd", "description-dd", &arg3) .MandatoryOption("--ee", "description-ee", &arg4) .OptionalFlag("--ff", "description-ff", &arg6) - .MandatoryOption("--gg", "description-gg", &arg7); + .MandatoryOption("--gg", "description-gg", &arg7) + .OptionalOption("--hh", "description-hh", &arg8); std::stringstream stream; opts.Usage(stream); const std::string s = stream.str(); ASSERT_NE(s.find("usage: test --aa arg [--bb] [--cc arg] [--dd arg] --ee arg [--ff] --gg arg " - "[--gg arg [..]]"), + "[--gg arg [..]] [--hh arg [..]]"), std::string::npos); ASSERT_NE(s.find("--aa arg description-aa"), std::string::npos); ASSERT_NE(s.find("--ff description-ff"), std::string::npos); diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp index 4bf832a34691..d9d9a7f829cf 100644 --- a/cmds/idmap2/tests/FileUtilsTests.cpp +++ b/cmds/idmap2/tests/FileUtilsTests.cpp @@ -37,10 +37,10 @@ TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) { [](unsigned char type ATTRIBUTE_UNUSED, const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; }); ASSERT_THAT(v, NotNull()); - ASSERT_EQ(v->size(), 4U); - ASSERT_EQ( - std::set<std::string>(v->begin(), v->end()), - std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target"})); + ASSERT_EQ(v->size(), 6U); + ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), + std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target", + root + "/system-overlay", root + "/system-overlay-invalid"})); } TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) { @@ -49,11 +49,13 @@ TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) { return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0; }); ASSERT_THAT(v, NotNull()); - ASSERT_EQ(v->size(), 4U); + ASSERT_EQ(v->size(), 6U); ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk", root + "/overlay/overlay-static-1.apk", - root + "/overlay/overlay-static-2.apk"})); + root + "/overlay/overlay-static-2.apk", + root + "/system-overlay/system-overlay.apk", + root + "/system-overlay-invalid/system-overlay-invalid.apk"})); } TEST(FileUtilsTests, ReadFile) { diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp index 22f48e9a396f..0c8f164bf096 100644 --- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp +++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp @@ -38,6 +38,7 @@ #include "gtest/gtest.h" #include "androidfw/PosixUtils.h" + #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" @@ -114,8 +115,9 @@ TEST_F(Idmap2BinaryTests, Dump) { ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos); - ASSERT_NE(result->stdout.find("0x7f020003 -> 0x7f020000 string/str1"), std::string::npos); - ASSERT_NE(result->stdout.find("0x7f020005 -> 0x7f020001 string/str3"), std::string::npos); + ASSERT_NE(result->stdout.find("0x7f020008 -> 0x7f020000 string/str1"), std::string::npos); + ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020001 string/str3"), std::string::npos); + ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020002 string/str4"), std::string::npos); ASSERT_EQ(result->stdout.find("00000210: 007f target package id"), std::string::npos); // clang-format off @@ -157,7 +159,8 @@ TEST_F(Idmap2BinaryTests, Scan) { "--recursive", "--target-package-name", "test.target", "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath()}); + "--output-directory", GetTempDirPath(), + "--override-policy", "public"}); // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; @@ -190,7 +193,8 @@ TEST_F(Idmap2BinaryTests, Scan) { "--input-directory", GetTestDataPath() + "/overlay", "--target-package-name", "test.target", "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath()}); + "--output-directory", GetTempDirPath(), + "--override-policy", "public"}); // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; @@ -207,7 +211,8 @@ TEST_F(Idmap2BinaryTests, Scan) { "--recursive", "--target-package-name", "test.target", "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath()}); + "--output-directory", GetTempDirPath(), + "--override-policy", "public"}); // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; @@ -222,7 +227,8 @@ TEST_F(Idmap2BinaryTests, Scan) { "--input-directory", GetTempDirPath(), "--target-package-name", "test.target", "--target-apk-path", GetTargetApkPath(), - "--output-directory", GetTempDirPath()}); + "--output-directory", GetTempDirPath(), + "--override-policy", "public"}); // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; @@ -245,7 +251,7 @@ TEST_F(Idmap2BinaryTests, Lookup) { "lookup", "--idmap-path", GetIdmapPath(), "--config", "", - "--resid", "0x7f020003"}); // string/str1 + "--resid", "0x7f020008"}); // string/str1 // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr; @@ -310,6 +316,18 @@ TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) { // clang-format on ASSERT_THAT(result, NotNull()); ASSERT_NE(result->status, EXIT_SUCCESS); + + // unknown policy + // clang-format off + result = ExecuteBinary({"idmap2", + "create", + "--target-apk-path", GetTargetApkPath(), + "--overlay-apk-path", GetOverlayApkPath(), + "--idmap-path", GetIdmapPath(), + "--policy", "this-does-not-exist"}); + // clang-format on + ASSERT_THAT(result, NotNull()); + ASSERT_NE(result->status, EXIT_SUCCESS); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 963f22ec8d72..c6eb71cbeb72 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -184,13 +184,14 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) { std::stringstream error; std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error); ASSERT_THAT(idmap, NotNull()); ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U); - ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xf5ad1d1d); + ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xca2093da); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path); ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path); @@ -216,13 +217,127 @@ TEST(IdmapTests, CreateIdmapFromApkAssets) { ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U); ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U); ASSERT_EQ(types[1]->GetEntryCount(), 4U); - ASSERT_EQ(types[1]->GetEntryOffset(), 3U); + ASSERT_EQ(types[1]->GetEntryOffset(), 8U); ASSERT_EQ(types[1]->GetEntry(0), 0x0000U); ASSERT_EQ(types[1]->GetEntry(1), kNoEntry); ASSERT_EQ(types[1]->GetEntry(2), 0x0001U); ASSERT_EQ(types[1]->GetEntry(3), 0x0002U); } +TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) { + const std::string target_apk_path(GetTestDataPath() + "/target/target.apk"); + std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); + ASSERT_THAT(target_apk, NotNull()); + + const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk"); + std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); + ASSERT_THAT(overlay_apk, NotNull()); + + std::stringstream error; + std::unique_ptr<const Idmap> idmap = + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ true, error); + ASSERT_THAT(idmap, NotNull()); + + const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); + ASSERT_EQ(dataBlocks.size(), 1U); + + const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; + + ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); + ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); + + const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); + ASSERT_EQ(types.size(), 1U); + + ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); + ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); + ASSERT_EQ(types[0]->GetEntryCount(), 3U); + ASSERT_EQ(types[0]->GetEntryOffset(), 5U); + ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_public + ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_system + ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_system_vendor +} + +TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) { + const std::string target_apk_path(GetTestDataPath() + "/target/target.apk"); + std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); + ASSERT_THAT(target_apk, NotNull()); + + const std::string overlay_apk_path(GetTestDataPath() + + "/system-overlay-invalid/system-overlay-invalid.apk"); + std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); + ASSERT_THAT(overlay_apk, NotNull()); + + std::stringstream error; + std::unique_ptr<const Idmap> idmap = + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ true, error); + ASSERT_THAT(idmap, NotNull()); + + const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); + ASSERT_EQ(dataBlocks.size(), 1U); + + const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; + + ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); + ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); + + const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); + ASSERT_EQ(types.size(), 1U); + + ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); + ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); + ASSERT_EQ(types[0]->GetEntryCount(), 5U); + ASSERT_EQ(types[0]->GetEntryOffset(), 3U); + ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable + ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_product + ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_public + ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_system + ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system_vendor +} + +TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) { + const std::string target_apk_path(GetTestDataPath() + "/target/target.apk"); + std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path); + ASSERT_THAT(target_apk, NotNull()); + + const std::string overlay_apk_path(GetTestDataPath() + + "/system-overlay-invalid/system-overlay-invalid.apk"); + std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); + ASSERT_THAT(overlay_apk, NotNull()); + + std::stringstream error; + std::unique_ptr<const Idmap> idmap = + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ false, error); + ASSERT_THAT(idmap, NotNull()); + + const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData(); + ASSERT_EQ(dataBlocks.size(), 1U); + + const std::unique_ptr<const IdmapData>& data = dataBlocks[0]; + + ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU); + ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U); + + const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries(); + ASSERT_EQ(types.size(), 1U); + + ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U); + ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U); + ASSERT_EQ(types[0]->GetEntryCount(), 5U); + ASSERT_EQ(types[0]->GetEntryOffset(), 3U); + ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable + ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_product + ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_public + ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_system + ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system_vendor +} + TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) { std::string target_apk_path(GetTestDataPath()); for (int i = 0; i < 32; i++) { @@ -239,7 +354,8 @@ TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) { std::stringstream error; std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error); ASSERT_THAT(idmap, IsNull()); } @@ -255,8 +371,9 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { ASSERT_THAT(overlay_apk, NotNull()); std::stringstream error; - std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error); + std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets( + target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC, + /* enforce_overlayable */ true, error); ASSERT_THAT(idmap, NotNull()); std::stringstream stream; diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp new file mode 100644 index 000000000000..ab567adc6f19 --- /dev/null +++ b/cmds/idmap2/tests/PoliciesTests.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string> + +#include "gtest/gtest.h" + +#include "TestHelpers.h" +#include "idmap2/Policies.h" + +using android::idmap2::PolicyBitmask; +using android::idmap2::PolicyFlags; + +namespace android::idmap2 { + +TEST(PoliciesTests, PoliciesToBitmasks) { + const Result<PolicyBitmask> bitmask1 = PoliciesToBitmask({"system"}, std::cerr); + ASSERT_NE(bitmask1, kResultError); + ASSERT_EQ(bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION); + + const Result<PolicyBitmask> bitmask2 = PoliciesToBitmask({"system", "vendor"}, std::cerr); + ASSERT_NE(bitmask2, kResultError); + ASSERT_EQ(bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION); + + const Result<PolicyBitmask> bitmask3 = PoliciesToBitmask({"vendor", "system"}, std::cerr); + ASSERT_NE(bitmask3, kResultError); + ASSERT_EQ(bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION); + + const Result<PolicyBitmask> bitmask4 = + PoliciesToBitmask({"public", "product", "system", "vendor"}, std::cerr); + ASSERT_NE(bitmask4, kResultError); + ASSERT_EQ(bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION | + PolicyFlags::POLICY_SYSTEM_PARTITION | + PolicyFlags::POLICY_VENDOR_PARTITION); + + const Result<PolicyBitmask> bitmask5 = + PoliciesToBitmask({"system", "system", "system"}, std::cerr); + ASSERT_NE(bitmask5, kResultError); + ASSERT_EQ(bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION); + + const Result<PolicyBitmask> bitmask6 = PoliciesToBitmask({""}, std::cerr); + ASSERT_EQ(bitmask6, kResultError); + + const Result<PolicyBitmask> bitmask7 = PoliciesToBitmask({"foo"}, std::cerr); + ASSERT_EQ(bitmask7, kResultError); + + const Result<PolicyBitmask> bitmask8 = PoliciesToBitmask({"system", "foo"}, std::cerr); + ASSERT_EQ(bitmask8, kResultError); + + const Result<PolicyBitmask> bitmask9 = PoliciesToBitmask({"system", ""}, std::cerr); + ASSERT_EQ(bitmask9, kResultError); + + const Result<PolicyBitmask> bitmask10 = PoliciesToBitmask({"system "}, std::cerr); + ASSERT_EQ(bitmask10, kResultError); +} + +} // namespace android::idmap2 diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp index 7736bc063131..eaa47cd79533 100644 --- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp @@ -25,6 +25,7 @@ #include "androidfw/Idmap.h" #include "idmap2/Idmap.h" +#include "idmap2/Policies.h" #include "idmap2/PrettyPrintVisitor.h" #include "TestHelpers.h" @@ -32,6 +33,7 @@ using ::testing::NotNull; using android::ApkAssets; +using android::idmap2::PolicyBitmask; namespace android::idmap2 { @@ -46,7 +48,8 @@ TEST(PrettyPrintVisitorTests, CreatePrettyPrintVisitor) { std::stringstream error; std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error); ASSERT_THAT(idmap, NotNull()); std::stringstream stream; diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index 0318cd20a9bb..b58c61a0c284 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -42,7 +42,8 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { std::stringstream error; std::unique_ptr<const Idmap> idmap = - Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error); + Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, + PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error); ASSERT_THAT(idmap, NotNull()); std::stringstream stream; @@ -51,7 +52,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos); ASSERT_NE(stream.str().find("00000004: 00000001 version\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000008: f5ad1d1d target crc\n"), std::string::npos); + ASSERT_NE(stream.str().find("00000008: ca2093da target crc\n"), std::string::npos); ASSERT_NE(stream.str().find("0000000c: d470336b overlay crc\n"), std::string::npos); ASSERT_NE(stream.str().find("0000021c: 00000000 0x7f010000 -> 0x7f010000 integer/int1\n"), std::string::npos); diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml new file mode 100644 index 000000000000..977cd97f21c3 --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="test.overlay.system.invalid"> + <overlay + android:targetPackage="test.target" /> +</manifest> diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build new file mode 100644 index 000000000000..920e1f8ad6f3 --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay-invalid/build @@ -0,0 +1,26 @@ +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar + +aapt2 compile --dir res -o compiled.flata + +aapt2 link \ + --no-resource-removal \ + -I "$FRAMEWORK_RES_APK" \ + --manifest AndroidManifest.xml \ + -o system-overlay-invalid.apk \ + compiled.flata + +rm compiled.flata diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml new file mode 100644 index 000000000000..512770722a4b --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- This overlay will fulfill the policies "public|system". This allows it overlay the + following resources. --> + <string name="policy_system">policy_system</string> + <string name="policy_system_vendor">policy_system_vendor</string> + <string name="policy_public">policy_public</string> + + <!-- It also requests to overlay a resource that belongs to a policy the overlay does not + fulfill.--> + <string name="policy_product">policy_product</string> + + <!-- It also requests to overlay a resource that is not declared as overlayable.--> + <string name="not_overlayable">not_overlayable</string> +</resources> diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk Binary files differnew file mode 100644 index 000000000000..c367f82e21e6 --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml new file mode 100644 index 000000000000..8af9064ba64f --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<manifest + xmlns:android="http://schemas.android.com/apk/res/android" + package="test.overlay.system"> + <overlay + android:targetPackage="test.target" /> +</manifest> diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build new file mode 100644 index 000000000000..be0d2390f535 --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay/build @@ -0,0 +1,26 @@ +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar + +aapt2 compile --dir res -o compiled.flata + +aapt2 link \ + --no-resource-removal \ + -I "$FRAMEWORK_RES_APK" \ + --manifest AndroidManifest.xml \ + -o system-overlay.apk \ + compiled.flata + +rm compiled.flata diff --git a/cmds/idmap2/tests/data/system-overlay/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml new file mode 100644 index 000000000000..6aaa0b02639e --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- This overlay will fulfill the policies "public|system". This allows it overlay the + following resources. --> + <string name="policy_system">policy_system</string> + <string name="policy_system_vendor">policy_system_vendor</string> + <string name="policy_public">policy_public</string> +</resources> diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk Binary files differnew file mode 100644 index 000000000000..90f30eb68c15 --- /dev/null +++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml new file mode 100644 index 000000000000..de19e6fcd022 --- /dev/null +++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> +<overlayable name="TestResources"> + <!-- Publicly overlayable resources --> + <item type="string" name="a" /> + <item type="string" name="b" /> + <item type="string" name="c" /> + <item type="string" name="str1" /> + <item type="string" name="str2" /> + <item type="string" name="str3" /> + <item type="string" name="str4" /> + <item type="string" name="x" /> + <item type="string" name="y" /> + <item type="string" name="z" /> + <item type="integer" name="int1" /> + + <!-- Resources with partition restrictins --> + <policy type="system"> + <item type="string" name="policy_system" /> + </policy> + + <policy type="system|vendor"> + <item type="string" name="policy_system_vendor" /> + </policy> + + <policy type="product"> + <item type="string" name="policy_product" /> + </policy> + + <policy type="public"> + <item type="string" name="policy_public" /> + </policy> +</overlayable> +</resources>
\ No newline at end of file diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml index 56bf0d60021a..ef9012e49300 100644 --- a/cmds/idmap2/tests/data/target/res/values/values.xml +++ b/cmds/idmap2/tests/data/target/res/values/values.xml @@ -25,4 +25,12 @@ <string name="y">y</string> <string name="z">z</string> <integer name="int1">1</integer> + + <!-- This resources is not marked as overlayable --> + <string name="not_overlayable">not_overlayable</string> + + <string name="policy_system">policy_system</string> + <string name="policy_system_vendor">policy_system_vendor</string> + <string name="policy_product">policy_product</string> + <string name="policy_public">policy_public</string> </resources> diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk Binary files differindex 18ecc276caae..9a6220dbe3ca 100644 --- a/cmds/idmap2/tests/data/target/target.apk +++ b/cmds/idmap2/tests/data/target/target.apk diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index f75e58406a83..7ceef999d6af 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3375,7 +3375,8 @@ message PackageAssociationSourceProcessStatsProto { optional int32 process_uid = 1; // Process name. optional string process_name = 2; - + // Package name. + optional string package_name = 7; // Total count of the times this association appeared. optional int32 total_count = 3; @@ -3454,6 +3455,9 @@ message ProcessStatsSectionProto { } repeated Status status = 7; + // Number of pages available of various types and sizes, representation fragmentation. + repeated ProcessStatsAvailablePagesProto available_pages = 10; + // Stats for each process. repeated ProcessStatsProto process_stats = 8; @@ -3461,6 +3465,21 @@ message ProcessStatsSectionProto { repeated ProcessStatsPackageProto package_stats = 9; } +message ProcessStatsAvailablePagesProto { + // Node these pages are in (as per /proc/pagetypeinfo) + optional int32 node = 1; + + // Zone these pages are in (as per /proc/pagetypeinfo) + optional string zone = 2; + + // Label for the type of these pages (as per /proc/pagetypeinfo) + optional string label = 3; + + // Distribution of number of pages available by order size. First entry in array is + // order 0, second is order 1, etc. Each order increase is a doubling of page size. + repeated int32 pages_per_order = 4; +} + /** * Pulled from ProcessStatsService.java */ diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index 5392a3c428c1..02eff0b6cee2 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -1108,18 +1108,6 @@ Landroid/os/UserManager;->isUserUnlocked(I)Z Landroid/os/UserManager;->mService:Landroid/os/IUserManager; Landroid/os/UserManager;->removeUser(I)Z Landroid/os/Vibrator;-><init>()V -Landroid/os/VintfObject;->getHalNamesAndVersions()[Ljava/lang/String; -Landroid/os/VintfObject;->getSepolicyVersion()Ljava/lang/String; -Landroid/os/VintfObject;->getTargetFrameworkCompatibilityMatrixVersion()Ljava/lang/Long; -Landroid/os/VintfObject;->getVndkSnapshots()Ljava/util/Map; -Landroid/os/VintfObject;->report()[Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getCpuInfo()Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getHardwareId()Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getKernelVersion()Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getNodeName()Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getOsName()Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getOsRelease()Ljava/lang/String; -Landroid/os/VintfRuntimeInfo;->getOsVersion()Ljava/lang/String; Landroid/os/WorkSource;-><init>(Landroid/os/Parcel;)V Landroid/os/WorkSource;->mNames:[Ljava/lang/String; Landroid/os/WorkSource;->mNum:I @@ -1824,22 +1812,10 @@ Lcom/android/internal/os/RuntimeInit;->getApplicationObject()Landroid/os/IBinder Lcom/android/internal/os/RuntimeInit;->initialized:Z Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder; -Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V -Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J -Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I -Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I -Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J -Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String; -Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList; -Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I -Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V Lcom/android/internal/os/ZygoteConnection;->closeSocket()V -Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor; -Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket; Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream; Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials; -Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String; Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources; Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d374f1c0acdf..836627efb379 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -124,6 +124,7 @@ import android.view.autofill.AutofillPopupWindow; import android.view.autofill.IAutofillWindowPresenter; import android.view.contentcapture.ContentCaptureContext; import android.view.contentcapture.ContentCaptureManager; +import android.view.contentcapture.ContentCaptureSession; import android.widget.AdapterView; import android.widget.Toast; import android.widget.Toolbar; @@ -1034,13 +1035,15 @@ public class Activity extends ContextThemeWrapper } /** @hide */ private static final int CONTENT_CAPTURE_START = 1; - /** @hide */ private static final int CONTENT_CAPTURE_FLUSH = 2; - /** @hide */ private static final int CONTENT_CAPTURE_STOP = 3; + /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 2; + /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 3; + /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4; /** @hide */ @IntDef(prefix = { "CONTENT_CAPTURE_" }, value = { CONTENT_CAPTURE_START, - CONTENT_CAPTURE_FLUSH, + CONTENT_CAPTURE_PAUSE, + CONTENT_CAPTURE_RESUME, CONTENT_CAPTURE_STOP }) @Retention(RetentionPolicy.SOURCE) @@ -1062,8 +1065,11 @@ public class Activity extends ContextThemeWrapper } cm.onActivityStarted(mToken, getComponentName(), flags); break; - case CONTENT_CAPTURE_FLUSH: - cm.flush(); + case CONTENT_CAPTURE_PAUSE: + cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_PAUSED); + break; + case CONTENT_CAPTURE_RESUME: + cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_RESUMED); break; case CONTENT_CAPTURE_STOP: cm.onActivityStopped(); @@ -1755,7 +1761,7 @@ public class Activity extends ContextThemeWrapper } } mCalled = true; - notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH); + notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME); } /** @@ -2149,7 +2155,7 @@ public class Activity extends ContextThemeWrapper } } mCalled = true; - notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH); + notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE); } /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index d27cce535c3b..8497656df2be 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -33,6 +33,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Rect; @@ -1954,6 +1955,17 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_LAUNCHER_EXTRAS = "android.intent.extra.LAUNCHER_EXTRAS"; /** + * Intent extra: ID of the shortcut used to send the share intent. + * + * @see ShortcutInfo#getId() + * + * <p> + * Type: String + * </p> + */ + public static final String EXTRA_SHORTCUT_ID = "android.intent.extra.shortcut.ID"; + + /** * Activity action: Launch UI to manage which apps have a given permission. * <p> * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission group diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl index 03124be7ab7d..c702b16c97f6 100644 --- a/core/java/android/content/pm/IShortcutService.aidl +++ b/core/java/android/content/pm/IShortcutService.aidl @@ -16,6 +16,7 @@ package android.content.pm; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; @@ -72,4 +73,7 @@ interface IShortcutService { void applyRestore(in byte[] payload, int user); boolean isRequestPinItemSupported(int user, int requestType); + + // System API used by framework's ShareSheet (ChooserActivity) + ParceledListSlice getShareTargets(String packageName, in IntentFilter filter, int userId); }
\ No newline at end of file diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index ec2e2fd474a2..fe68b8a048c2 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; +import android.app.Person; import android.app.TaskStackBuilder; import android.content.ComponentName; import android.content.Context; @@ -111,6 +112,9 @@ public final class ShortcutInfo implements Parcelable { public static final int FLAG_SHADOW = 1 << 12; /** @hide */ + public static final int FLAG_LONG_LIVED = 1 << 13; + + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DYNAMIC, FLAG_PINNED, @@ -124,6 +128,8 @@ public final class ShortcutInfo implements Parcelable { FLAG_ADAPTIVE_BITMAP, FLAG_RETURNED_BY_SERVICE, FLAG_ICON_FILE_PENDING_SAVE, + FLAG_SHADOW, + FLAG_LONG_LIVED, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} @@ -344,6 +350,9 @@ public final class ShortcutInfo implements Parcelable { @Nullable private PersistableBundle[] mIntentPersistableExtrases; + @Nullable + private Person[] mPersons; + private int mRank; /** @@ -399,6 +408,10 @@ public final class ShortcutInfo implements Parcelable { mCategories = cloneCategories(b.mCategories); mIntents = cloneIntents(b.mIntents); fixUpIntentExtras(); + mPersons = clonePersons(b.mPersons); + if (b.mIsLongLived) { + setLongLived(); + } mRank = b.mRank; mExtras = b.mExtras; updateTimestamp(); @@ -465,6 +478,20 @@ public final class ShortcutInfo implements Parcelable { return ret; } + private static Person[] clonePersons(Person[] persons) { + if (persons == null) { + return null; + } + final Person[] ret = new Person[persons.length]; + for (int i = 0; i < ret.length; i++) { + if (persons[i] != null) { + // Don't need to keep the icon, remove it to save space + ret[i] = persons[i].toBuilder().setIcon(null).build(); + } + } + return ret; + } + /** * Throws if any of the mandatory fields is not set. * @@ -511,6 +538,7 @@ public final class ShortcutInfo implements Parcelable { mDisabledMessage = source.mDisabledMessage; mDisabledMessageResId = source.mDisabledMessageResId; mCategories = cloneCategories(source.mCategories); + mPersons = clonePersons(source.mPersons); if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) { mIntents = cloneIntents(source.mIntents); mIntentPersistableExtrases = @@ -833,6 +861,9 @@ public final class ShortcutInfo implements Parcelable { if (source.mCategories != null) { mCategories = cloneCategories(source.mCategories); } + if (source.mPersons != null) { + mPersons = clonePersons(source.mPersons); + } if (source.mIntents != null) { mIntents = cloneIntents(source.mIntents); mIntentPersistableExtrases = @@ -901,6 +932,10 @@ public final class ShortcutInfo implements Parcelable { private Intent[] mIntents; + private Person[] mPersons; + + private boolean mIsLongLived; + private int mRank = RANK_NOT_SET; private PersistableBundle mExtras; @@ -1165,6 +1200,53 @@ public final class ShortcutInfo implements Parcelable { } /** + * Add a person that is relevant to this shortcut. Alternatively, + * {@link #setPersons(Person[])} can be used to add multiple persons to a shortcut. + * + * <p> This is an optional field, but the addition of person may cause this shortcut to + * appear more prominently in the user interface (e.g. ShareSheet). + * + * <p> A person should usually contain a uri in order to benefit from the ranking boost. + * However, even if no uri is provided, it's beneficial to provide people in the shortcut, + * such that listeners and voice only devices can announce and handle them properly. + * + * @see Person + * @see #setPersons(Person[]) + */ + @NonNull + public Builder setPerson(@NonNull Person person) { + return setPersons(new Person[]{person}); + } + + /** + * Sets multiple persons instead of a single person. + * + * @see Person + * @see #setPerson(Person) + */ + @NonNull + public Builder setPersons(@NonNull Person[] persons) { + Preconditions.checkNotNull(persons, "persons cannot be null"); + Preconditions.checkNotNull(persons.length, "persons cannot be empty"); + for (Person person : persons) { + Preconditions.checkNotNull(person, "persons cannot contain null"); + } + mPersons = clonePersons(persons); + return this; + } + + /** + * Sets if a shortcut would be valid even if it has been unpublished/invisible by the app + * (as a dynamic or pinned shortcut). If it is long lived, it can be cached by various + * system services even after it has been unpublished as a dynamic shortcut. + */ + @NonNull + public Builder setLongLived() { + mIsLongLived = true; + return this; + } + + /** * "Rank" of a shortcut, which is a non-negative value that's used by the launcher app * to sort shortcuts. * @@ -1395,6 +1477,16 @@ public final class ShortcutInfo implements Parcelable { } /** + * Return the Persons set with {@link Builder#setPersons(Person[])}. + * + * @hide + */ + @Nullable + public Person[] getPersons() { + return clonePersons(mPersons); + } + + /** * The extras in the intents. We convert extras into {@link PersistableBundle} so we can * persist them. * @hide @@ -1525,6 +1617,16 @@ public final class ShortcutInfo implements Parcelable { addFlags(FLAG_RETURNED_BY_SERVICE); } + /** @hide */ + public boolean isLongLived() { + return hasFlags(FLAG_LONG_LIVED); + } + + /** @hide */ + public void setLongLived() { + addFlags(FLAG_LONG_LIVED); + } + /** Return whether a shortcut is dynamic. */ public boolean isDynamic() { return hasFlags(FLAG_DYNAMIC); @@ -1893,6 +1995,8 @@ public final class ShortcutInfo implements Parcelable { mCategories.add(source.readString().intern()); } } + + mPersons = source.readParcelableArray(cl, Person.class); } @Override @@ -1940,6 +2044,8 @@ public final class ShortcutInfo implements Parcelable { } else { dest.writeInt(0); } + + dest.writeParcelableArray(mPersons, flags); } public static final Creator<ShortcutInfo> CREATOR = @@ -2040,6 +2146,9 @@ public final class ShortcutInfo implements Parcelable { if (isReturnedByServer()) { sb.append("Rets"); } + if (isLongLived()) { + sb.append("Liv"); + } sb.append("]"); addIndentOrComma(sb, indent); @@ -2094,6 +2203,11 @@ public final class ShortcutInfo implements Parcelable { addIndentOrComma(sb, indent); + sb.append("persons="); + sb.append(mPersons); + + addIndentOrComma(sb, indent); + sb.append("icon="); sb.append(mIcon); diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index 2d590033259f..4f7acd96aa6b 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -17,17 +17,22 @@ package android.content.pm; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.annotation.UserIdInt; import android.app.usage.UsageStatsManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.graphics.drawable.AdaptiveIconDrawable; import android.os.Build; import android.os.Build.VERSION_CODES; +import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; @@ -549,4 +554,85 @@ public class ShortcutManager { protected int injectMyUserId() { return mContext.getUserId(); } + + /** + * Used by framework's ShareSheet (ChooserActivity.java) to retrieve all of the direct share + * targets that match the given IntentFilter. + * + * @param filter IntentFilter that will be used to retrieve the matching {@link ShortcutInfo}s. + * @return List of {@link ShareShortcutInfo}s that match the given IntentFilter. + * @hide + */ + @NonNull + @SystemApi + public List<ShareShortcutInfo> getShareTargets(@NonNull IntentFilter filter) { + try { + return mService.getShareTargets(mContext.getPackageName(), filter, + injectMyUserId()).getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Represents the result of a query return by {@link #getShareTargets(IntentFilter)}. + * + * @hide + */ + @SystemApi + public static final class ShareShortcutInfo implements Parcelable { + private final ShortcutInfo mShortcutInfo; + private final ComponentName mTargetComponent; + + /** + * @hide + */ + public ShareShortcutInfo(@NonNull ShortcutInfo shortcutInfo, + @NonNull ComponentName targetComponent) { + if (shortcutInfo == null) { + throw new NullPointerException("shortcut info is null"); + } + if (targetComponent == null) { + throw new NullPointerException("target component is null"); + } + + mShortcutInfo = shortcutInfo; + mTargetComponent = targetComponent; + } + + private ShareShortcutInfo(Parcel in) { + mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader()); + mTargetComponent = in.readParcelable(ComponentName.class.getClassLoader()); + } + + public ShortcutInfo getShortcutInfo() { + return mShortcutInfo; + } + + public ComponentName getTargetComponent() { + return mTargetComponent; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mShortcutInfo, flags); + dest.writeParcelable(mTargetComponent, flags); + } + + public static final Parcelable.Creator<ShareShortcutInfo> CREATOR = + new Parcelable.Creator<ShareShortcutInfo>() { + public ShareShortcutInfo createFromParcel(Parcel in) { + return new ShareShortcutInfo(in); + } + + public ShareShortcutInfo[] newArray(int size) { + return new ShareShortcutInfo[size]; + } + }; + } } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index c4b315ec90c8..dcd6e2ed94c7 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -98,6 +98,12 @@ import java.util.ArrayList; * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p> */ public class Resources { + /** + * The {@code null} resource ID. This denotes an invalid resource ID that is returned by the + * system when a resource is not found or the value is set to {@code @null} in XML. + */ + public static final @AnyRes int ID_NULL = 0; + static final String TAG = "Resources"; private static final Object sSync = new Object(); diff --git a/core/java/android/hardware/display/BrightnessConfiguration.java b/core/java/android/hardware/display/BrightnessConfiguration.java index be054297c769..8c74ddc7698c 100644 --- a/core/java/android/hardware/display/BrightnessConfiguration.java +++ b/core/java/android/hardware/display/BrightnessConfiguration.java @@ -91,9 +91,7 @@ public final class BrightnessConfiguration implements Parcelable { * * @return The matching brightness correction, or null. * - * @hide */ - @SystemApi @Nullable public BrightnessCorrection getCorrectionByPackageName(String packageName) { return mCorrectionsByPackageName.get(packageName); @@ -106,10 +104,7 @@ public final class BrightnessConfiguration implements Parcelable { * The app category. * * @return The matching brightness correction, or null. - * - * @hide */ - @SystemApi @Nullable public BrightnessCorrection getCorrectionByCategory(int category) { return mCorrectionsByCategory.get(category); @@ -416,9 +411,7 @@ public final class BrightnessConfiguration implements Parcelable { * * @return The maximum number of corrections by package name allowed. * - * @hide */ - @SystemApi public int getMaxCorrectionsByPackageName() { return MAX_CORRECTIONS_BY_PACKAGE_NAME; } @@ -428,9 +421,7 @@ public final class BrightnessConfiguration implements Parcelable { * * @return The maximum number of corrections by category allowed. * - * @hide */ - @SystemApi public int getMaxCorrectionsByCategory() { return MAX_CORRECTIONS_BY_CATEGORY; } @@ -451,9 +442,7 @@ public final class BrightnessConfiguration implements Parcelable { * Maximum number of corrections by package name exceeded (see * {@link #getMaxCorrectionsByPackageName}). * - * @hide */ - @SystemApi public Builder addCorrectionByPackageName(String packageName, BrightnessCorrection correction) { if (mCorrectionsByPackageName.size() >= getMaxCorrectionsByPackageName()) { @@ -479,9 +468,7 @@ public final class BrightnessConfiguration implements Parcelable { * Maximum number of corrections by category exceeded (see * {@link #getMaxCorrectionsByCategory}). * - * @hide */ - @SystemApi public Builder addCorrectionByCategory(@ApplicationInfo.Category int category, BrightnessCorrection correction) { if (mCorrectionsByCategory.size() >= getMaxCorrectionsByCategory()) { @@ -504,8 +491,6 @@ public final class BrightnessConfiguration implements Parcelable { /** * Builds the {@link BrightnessConfiguration}. - * - * A brightness curve <b>must</b> be set before calling this. */ public BrightnessConfiguration build() { if (mCurveLux == null || mCurveNits == null) { diff --git a/core/java/android/hardware/display/BrightnessCorrection.java b/core/java/android/hardware/display/BrightnessCorrection.java index c4e0e3b723cd..6a073ffaaa5b 100644 --- a/core/java/android/hardware/display/BrightnessCorrection.java +++ b/core/java/android/hardware/display/BrightnessCorrection.java @@ -18,6 +18,7 @@ package android.hardware.display; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.util.MathUtils; @@ -41,6 +42,7 @@ import java.io.IOException; * @hide */ @SystemApi +@TestApi public final class BrightnessCorrection implements Parcelable { private static final int SCALE_AND_TRANSLATE_LOG = 1; @@ -98,6 +100,24 @@ public final class BrightnessCorrection implements Parcelable { return mImplementation.toString(); } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof BrightnessCorrection)) { + return false; + } + BrightnessCorrection other = (BrightnessCorrection) o; + return other.mImplementation.equals(mImplementation); + } + + @Override + public int hashCode() { + return mImplementation.hashCode(); + } + public static final Creator<BrightnessCorrection> CREATOR = new Creator<BrightnessCorrection>() { public BrightnessCorrection createFromParcel(Parcel in) { @@ -215,6 +235,26 @@ public final class BrightnessCorrection implements Parcelable { } @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ScaleAndTranslateLog)) { + return false; + } + ScaleAndTranslateLog other = (ScaleAndTranslateLog) o; + return other.mScale == mScale && other.mTranslate == mTranslate; + } + + @Override + public int hashCode() { + int result = 1; + result = result * 31 + Float.hashCode(mScale); + result = result * 31 + Float.hashCode(mTranslate); + return result; + } + + @Override public void writeToParcel(Parcel dest) { dest.writeInt(SCALE_AND_TRANSLATE_LOG); dest.writeFloat(mScale); diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java index be2f9551daff..fcfb72035c19 100644 --- a/core/java/android/net/NetworkSpecifier.java +++ b/core/java/android/net/NetworkSpecifier.java @@ -17,7 +17,7 @@ package android.net; /** - * Describes specific properties of a network for use in a {@link NetworkRequest}. + * Describes specific properties of a requested network for use in a {@link NetworkRequest}. * * Applications cannot instantiate this class by themselves, but can obtain instances of * subclasses of this class via other APIs. @@ -49,4 +49,29 @@ public abstract class NetworkSpecifier { public void assertValidFromUid(int requestorUid) { // empty } + + /** + * Optional method which can be overridden by concrete implementations of NetworkSpecifier to + * perform any redaction of information from the NetworkSpecifier, e.g. if it contains + * sensitive information. The default implementation simply returns the object itself - i.e. + * no information is redacted. A concrete implementation may return a modified (copy) of the + * NetworkSpecifier, or even return a null to fully remove all information. + * <p> + * This method is relevant to NetworkSpecifier objects used by agents - those are shared with + * apps by default. Some agents may store sensitive matching information in the specifier, + * e.g. a Wi-Fi SSID (which should not be shared since it may leak location). Those classes + * can redact to a null. Other agents use the Network Specifier to share public information + * with apps - those should not be redacted. + * <p> + * The default implementation redacts no information. + * + * @return A NetworkSpecifier object to be passed along to the requesting app. + * + * @hide + */ + public NetworkSpecifier redact() { + // TODO (b/122160111): convert default to null once all platform NetworkSpecifiers + // implement this method. + return this; + } } diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java index e4622dbdc379..f51ba9a41a2b 100644 --- a/core/java/android/os/GraphicsEnvironment.java +++ b/core/java/android/os/GraphicsEnvironment.java @@ -306,9 +306,18 @@ public class GraphicsEnvironment { String packageName, String paths, String devOptIn) { - // Check for temporary rules if debuggable or root - if (!isDebuggable(context) && !(getCanLoadSystemLibraries() == 1)) { - Log.v(TAG, "Skipping loading temporary rules file"); + /** + * We only want to load a temp rules file for: + * - apps that are marked 'debuggable' in their manifest + * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for + * debugging (PR_SET_DUMPABLE). + */ + boolean appIsDebuggable = isDebuggable(context); + boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1; + if (!(appIsDebuggable || deviceIsDebuggable)) { + Log.v(TAG, "Skipping loading temporary rules file: " + + "appIsDebuggable = " + appIsDebuggable + ", " + + "adbRootEnabled = " + deviceIsDebuggable); return false; } diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java index fb22194098b6..23c54f450a67 100644 --- a/core/java/android/os/VintfObject.java +++ b/core/java/android/os/VintfObject.java @@ -16,23 +16,27 @@ package android.os; -import java.util.Map; +import android.annotation.TestApi; +import java.util.Map; /** * Java API for libvintf. + * * @hide */ +@TestApi public class VintfObject { - /// ---------- OTA - /** * Slurps all device information (both manifests and both matrices) * and report them. * If any error in getting one of the manifests, it is not included in * the list. + * + * @hide */ + @TestApi public static native String[] report(); /** @@ -44,6 +48,8 @@ public class VintfObject { * @return = 0 if success (compatible) * > 0 if incompatible * < 0 if any error (mount partition fails, illformed XML, etc.) + * + * @hide */ public static native int verify(String[] packageInfo); @@ -55,22 +61,28 @@ public class VintfObject { * @return = 0 if success (compatible) * > 0 if incompatible * < 0 if any error (mount partition fails, illformed XML, etc.) + * + * @hide */ public static native int verifyWithoutAvb(); - /// ---------- CTS Device Info - /** * @return a list of HAL names and versions that is supported by this * device as stated in device and framework manifests. For example, * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0", * "android.hardware.camera.device@3.2"]. There are no duplicates. + * + * @hide */ + @TestApi public static native String[] getHalNamesAndVersions(); /** * @return the BOARD_SEPOLICY_VERS build flag available in device manifest. + * + * @hide */ + @TestApi public static native String getSepolicyVersion(); /** @@ -78,13 +90,22 @@ public class VintfObject { * specified in framework manifest. For example, * [("27", ["libjpeg.so", "libbase.so"]), * ("28", ["libjpeg.so", "libbase.so"])] + * + * @hide */ + @TestApi public static native Map<String, String[]> getVndkSnapshots(); /** - * @return target FCM version, a number specified in the device manifest - * indicating the FCM version that the device manifest implements. Null if - * device manifest doesn't specify this number (for legacy devices). + * @return Target Framework Compatibility Matrix (FCM) version, a number + * specified in the device manifest indicating the FCM version that the + * device manifest implements. Null if device manifest doesn't specify this + * number (for legacy devices). + * + * @hide */ + @TestApi public static native Long getTargetFrameworkCompatibilityMatrixVersion(); + + private VintfObject() {} } diff --git a/core/java/android/os/VintfRuntimeInfo.java b/core/java/android/os/VintfRuntimeInfo.java index 29698b9fa684..f17039ba9bf4 100644 --- a/core/java/android/os/VintfRuntimeInfo.java +++ b/core/java/android/os/VintfRuntimeInfo.java @@ -16,55 +16,84 @@ package android.os; +import android.annotation.TestApi; + /** * Java API for ::android::vintf::RuntimeInfo. Methods return null / 0 on any error. * * @hide */ +@TestApi public class VintfRuntimeInfo { private VintfRuntimeInfo() {} /** * @return /sys/fs/selinux/policyvers, via security_policyvers() native call + * + * @hide */ public static native long getKernelSepolicyVersion(); /** * @return content of /proc/cpuinfo + * + * @hide */ + @TestApi public static native String getCpuInfo(); /** * @return os name extracted from uname() native call + * + * @hide */ + @TestApi public static native String getOsName(); /** * @return node name extracted from uname() native call + * + * @hide */ + @TestApi public static native String getNodeName(); /** * @return os release extracted from uname() native call + * + * @hide */ + @TestApi public static native String getOsRelease(); /** * @return os version extracted from uname() native call + * + * @hide */ + @TestApi public static native String getOsVersion(); /** * @return hardware id extracted from uname() native call + * + * @hide */ + @TestApi public static native String getHardwareId(); /** * @return kernel version extracted from uname() native call. Format is * {@code x.y.z}. + * + * @hide */ + @TestApi public static native String getKernelVersion(); /** * @return libavb version in OS. Format is {@code x.y}. + * + * @hide */ public static native String getBootAvbVersion(); /** * @return libavb version in bootloader. Format is {@code x.y}. + * + * @hide */ public static native String getBootVbmetaAvbVersion(); - } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 44cb2212cd0c..af8146e85ec0 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -53,6 +53,13 @@ public final class DeviceConfig { public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config"); /** + * Namespace for all Game Driver features. + * @hide + */ + @SystemApi + public static final String NAMESPACE_GAME_DRIVER = "game_driver"; + + /** * Namespace for all input-related features that are used at the native level. * These features are applied at reboot. * diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java index 8e37559001db..e931826d2455 100644 --- a/core/java/android/provider/FontsContract.java +++ b/core/java/android/provider/FontsContract.java @@ -34,6 +34,7 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.FontStyle; import android.graphics.fonts.FontVariationAxis; import android.net.Uri; +import android.os.Build.VERSION_CODES; import android.os.CancellationSignal; import android.os.Handler; import android.os.HandlerThread; @@ -651,7 +652,16 @@ public class FontsContract { if (familyBuilder == null) { familyBuilder = new FontFamily.Builder(font); } else { - familyBuilder.addFont(font); + try { + familyBuilder.addFont(font); + } catch (IllegalArgumentException e) { + if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) { + // Surpress the IllegalArgumentException for keeping the backward + // compatibility. + continue; + } + throw e; + } } } catch (IOException e) { continue; diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java index ffd4156b5bfd..dc7c343c2c3e 100644 --- a/core/java/android/view/LayoutInflater.java +++ b/core/java/android/view/LayoutInflater.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; @@ -29,6 +30,7 @@ import android.graphics.Canvas; import android.os.Build; import android.os.Handler; import android.os.Message; +import android.os.SystemProperties; import android.os.Trace; import android.util.AttributeSet; import android.util.Log; @@ -38,6 +40,9 @@ import android.widget.FrameLayout; import com.android.internal.R; +import dalvik.system.PathClassLoader; +import java.io.File; +import java.lang.reflect.Method; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -72,6 +77,10 @@ public abstract class LayoutInflater { private static final String TAG = LayoutInflater.class.getSimpleName(); private static final boolean DEBUG = false; + private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY + = "view.precompiled_layout_enabled"; + private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex"; + /** Empty stack trace used to avoid log spam in re-throw exceptions. */ private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; @@ -93,6 +102,13 @@ public abstract class LayoutInflater { private Factory2 mPrivateFactory; private Filter mFilter; + // Indicates whether we should try to inflate layouts using a precompiled layout instead of + // inflating from the XML resource. + private boolean mUseCompiledView; + // This variable holds the classloader that will be used to look for precompiled layouts. The + // The classloader includes the generated compiled_view.dex file. + private ClassLoader mPrecompiledClassLoader; + @UnsupportedAppUsage final Object[] mConstructorArgs = new Object[2]; @@ -223,6 +239,7 @@ public abstract class LayoutInflater { */ protected LayoutInflater(Context context) { mContext = context; + initPrecompiledViews(); } /** @@ -239,6 +256,7 @@ public abstract class LayoutInflater { mFactory2 = original.mFactory2; mPrivateFactory = original.mPrivateFactory; setFilter(original.mFilter); + initPrecompiledViews(); } /** @@ -380,6 +398,41 @@ public abstract class LayoutInflater { } } + private void initPrecompiledViews() { + // Check if precompiled layouts are enabled by a system property. + mUseCompiledView = + SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false); + if (!mUseCompiledView) { + return; + } + + // Make sure the application allows code generation + ApplicationInfo appInfo = mContext.getApplicationInfo(); + if ((appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY) != 0 + || appInfo.isPrivilegedApp()) { + mUseCompiledView = false; + return; + } + + // Try to load the precompiled layout file. + try { + mPrecompiledClassLoader = mContext.getClassLoader(); + String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME; + if (new File(dexFile).exists()) { + mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader); + } else { + // If the precompiled layout file doesn't exist, then disable precompiled + // layouts. + mUseCompiledView = false; + } + } catch (Throwable e) { + if (DEBUG) { + Log.e(TAG, "Failed to initialized precompiled views layouts", e); + } + mUseCompiledView = false; + } + } + /** * Inflate a new view hierarchy from the specified xml resource. Throws * {@link InflateException} if there is an error. @@ -436,10 +489,14 @@ public abstract class LayoutInflater { final Resources res = getContext().getResources(); if (DEBUG) { Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" (" - + Integer.toHexString(resource) + ")"); + + Integer.toHexString(resource) + ")"); } - final XmlResourceParser parser = res.getLayout(resource); + View view = tryInflatePrecompiled(resource, res, root, attachToRoot); + if (view != null) { + return view; + } + XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { @@ -447,6 +504,73 @@ public abstract class LayoutInflater { } } + private @Nullable + View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root, + boolean attachToRoot) { + if (!mUseCompiledView) { + return null; + } + + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)"); + + // Try to inflate using a precompiled layout. + String pkg = res.getResourcePackageName(resource); + String layout = res.getResourceEntryName(resource); + + try { + Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView"); + Method inflater = clazz.getMethod(layout, Context.class, int.class); + View view = (View) inflater.invoke(null, mContext, resource); + + if (view != null && root != null) { + // We were able to use the precompiled inflater, but now we need to do some work to + // attach the view to the root correctly. + XmlResourceParser parser = res.getLayout(resource); + try { + AttributeSet attrs = Xml.asAttributeSet(parser); + advanceToRootNode(parser); + ViewGroup.LayoutParams params = root.generateLayoutParams(attrs); + + if (attachToRoot) { + root.addView(view, params); + } else { + view.setLayoutParams(params); + } + } finally { + parser.close(); + } + } + + return view; + } catch (Throwable e) { + if (DEBUG) { + Log.e(TAG, "Failed to use precompiled view", e); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + return null; + } + + /** + * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is + * found. + */ + private void advanceToRootNode(XmlPullParser parser) + throws InflateException, IOException, XmlPullParserException { + // Look for the root node. + int type; + while ((type = parser.next()) != XmlPullParser.START_TAG && + type != XmlPullParser.END_DOCUMENT) { + // Empty + } + + if (type != XmlPullParser.START_TAG) { + throw new InflateException(parser.getPositionDescription() + + ": No start tag found!"); + } + } + /** * Inflate a new view hierarchy from the specified XML node. Throws * {@link InflateException} if there is an error. @@ -480,18 +604,7 @@ public abstract class LayoutInflater { View result = root; try { - // Look for the root node. - int type; - while ((type = parser.next()) != XmlPullParser.START_TAG && - type != XmlPullParser.END_DOCUMENT) { - // Empty - } - - if (type != XmlPullParser.START_TAG) { - throw new InflateException(parser.getPositionDescription() - + ": No start tag found!"); - } - + advanceToRootNode(parser); final String name = parser.getName(); if (DEBUG) { @@ -994,82 +1107,85 @@ public abstract class LayoutInflater { + "reference. The layout ID " + value + " is not valid."); } - final XmlResourceParser childParser = context.getResources().getLayout(layout); + final View precompiled = tryInflatePrecompiled(layout, context.getResources(), + (ViewGroup) parent, /*attachToRoot=*/true); + if (precompiled == null) { + final XmlResourceParser childParser = context.getResources().getLayout(layout); - try { - final AttributeSet childAttrs = Xml.asAttributeSet(childParser); + try { + final AttributeSet childAttrs = Xml.asAttributeSet(childParser); - while ((type = childParser.next()) != XmlPullParser.START_TAG && - type != XmlPullParser.END_DOCUMENT) { - // Empty. - } + while ((type = childParser.next()) != XmlPullParser.START_TAG && + type != XmlPullParser.END_DOCUMENT) { + // Empty. + } - if (type != XmlPullParser.START_TAG) { - throw new InflateException(childParser.getPositionDescription() + - ": No start tag found!"); - } + if (type != XmlPullParser.START_TAG) { + throw new InflateException(childParser.getPositionDescription() + + ": No start tag found!"); + } - final String childName = childParser.getName(); + final String childName = childParser.getName(); - if (TAG_MERGE.equals(childName)) { - // The <merge> tag doesn't support android:theme, so - // nothing special to do here. - rInflate(childParser, parent, context, childAttrs, false); - } else { - final View view = createViewFromTag(parent, childName, - context, childAttrs, hasThemeOverride); - final ViewGroup group = (ViewGroup) parent; - - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.Include); - final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID); - final int visibility = a.getInt(R.styleable.Include_visibility, -1); - a.recycle(); - - // We try to load the layout params set in the <include /> tag. - // If the parent can't generate layout params (ex. missing width - // or height for the framework ViewGroups, though this is not - // necessarily true of all ViewGroups) then we expect it to throw - // a runtime exception. - // We catch this exception and set localParams accordingly: true - // means we successfully loaded layout params from the <include> - // tag, false means we need to rely on the included layout params. - ViewGroup.LayoutParams params = null; - try { - params = group.generateLayoutParams(attrs); - } catch (RuntimeException e) { - // Ignore, just fail over to child attrs. - } - if (params == null) { - params = group.generateLayoutParams(childAttrs); - } - view.setLayoutParams(params); + if (TAG_MERGE.equals(childName)) { + // The <merge> tag doesn't support android:theme, so + // nothing special to do here. + rInflate(childParser, parent, context, childAttrs, false); + } else { + final View view = createViewFromTag(parent, childName, + context, childAttrs, hasThemeOverride); + final ViewGroup group = (ViewGroup) parent; + + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.Include); + final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID); + final int visibility = a.getInt(R.styleable.Include_visibility, -1); + a.recycle(); + + // We try to load the layout params set in the <include /> tag. + // If the parent can't generate layout params (ex. missing width + // or height for the framework ViewGroups, though this is not + // necessarily true of all ViewGroups) then we expect it to throw + // a runtime exception. + // We catch this exception and set localParams accordingly: true + // means we successfully loaded layout params from the <include> + // tag, false means we need to rely on the included layout params. + ViewGroup.LayoutParams params = null; + try { + params = group.generateLayoutParams(attrs); + } catch (RuntimeException e) { + // Ignore, just fail over to child attrs. + } + if (params == null) { + params = group.generateLayoutParams(childAttrs); + } + view.setLayoutParams(params); - // Inflate all children. - rInflateChildren(childParser, view, childAttrs, true); + // Inflate all children. + rInflateChildren(childParser, view, childAttrs, true); - if (id != View.NO_ID) { - view.setId(id); - } + if (id != View.NO_ID) { + view.setId(id); + } - switch (visibility) { - case 0: - view.setVisibility(View.VISIBLE); - break; - case 1: - view.setVisibility(View.INVISIBLE); - break; - case 2: - view.setVisibility(View.GONE); - break; - } + switch (visibility) { + case 0: + view.setVisibility(View.VISIBLE); + break; + case 1: + view.setVisibility(View.INVISIBLE); + break; + case 2: + view.setVisibility(View.GONE); + break; + } - group.addView(view); + group.addView(view); + } + } finally { + childParser.close(); } - } finally { - childParser.close(); } - LayoutInflater.consumeChildElements(parser); } diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index cf11fd04efdf..c3d13bd46eb3 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -31,6 +31,7 @@ import android.graphics.RectF; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.hardware.display.DisplayManager; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -144,7 +145,8 @@ public final class PointerIcon implements Parcelable { public static final int TYPE_DEFAULT = TYPE_ARROW; private static final PointerIcon gNullIcon = new PointerIcon(TYPE_NULL); - private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>(); + private static final SparseArray<SparseArray<PointerIcon>> gSystemIconsByDisplay = + new SparseArray<SparseArray<PointerIcon>>(); private static boolean sUseLargeIcons = false; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) @@ -163,6 +165,12 @@ public final class PointerIcon implements Parcelable { @UnsupportedAppUsage private int mDurationPerFrame; + /** + * Listener for displays lifecycle. + * @hide + */ + private static DisplayManager.DisplayListener sDisplayListener; + private PointerIcon(int type) { mType = type; } @@ -211,7 +219,19 @@ public final class PointerIcon implements Parcelable { return gNullIcon; } - PointerIcon icon = gSystemIcons.get(type); + if (sDisplayListener == null) { + registerDisplayListener(context); + } + + final int displayId = context.getDisplayId(); + SparseArray<PointerIcon> systemIcons = gSystemIconsByDisplay.get(displayId); + if (systemIcons == null) { + systemIcons = new SparseArray<>(); + gSystemIconsByDisplay.put(displayId, systemIcons); + } + + PointerIcon icon = systemIcons.get(type); + // Reload if not in the same display. if (icon != null) { return icon; } @@ -240,7 +260,7 @@ public final class PointerIcon implements Parcelable { } else { icon.loadResource(context, context.getResources(), resourceId); } - gSystemIcons.append(type, icon); + systemIcons.append(type, icon); return icon; } @@ -250,7 +270,7 @@ public final class PointerIcon implements Parcelable { */ public static void setUseLargeIcons(boolean use) { sUseLargeIcons = use; - gSystemIcons.clear(); + gSystemIconsByDisplay.clear(); } /** @@ -576,4 +596,30 @@ public final class PointerIcon implements Parcelable { return 0; } } + + /** + * Manage system icon cache handled by display lifecycle. + * @param context The context. + */ + private static void registerDisplayListener(@NonNull Context context) { + sDisplayListener = new DisplayManager.DisplayListener() { + @Override + public void onDisplayAdded(int displayId) { + } + + @Override + public void onDisplayRemoved(int displayId) { + gSystemIconsByDisplay.remove(displayId); + } + + @Override + public void onDisplayChanged(int displayId) { + gSystemIconsByDisplay.remove(displayId); + } + }; + + DisplayManager displayManager = context.getSystemService(DisplayManager.class); + displayManager.registerDisplayListener(sDisplayListener, null /* handler */); + } + } diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ff5120d09e25..5e98236f7535 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -30,6 +30,7 @@ import static android.view.SurfaceControlProto.NAME; import android.annotation.Size; import android.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; +import android.graphics.ColorSpace; import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.PixelFormat; @@ -141,6 +142,7 @@ public class SurfaceControl implements Parcelable { private static native int nativeGetActiveConfig(IBinder displayToken); private static native boolean nativeSetActiveConfig(IBinder displayToken, int id); private static native int[] nativeGetDisplayColorModes(IBinder displayToken); + private static native int[] nativeGetCompositionDataspaces(); private static native int nativeGetActiveColorMode(IBinder displayToken); private static native boolean nativeSetActiveColorMode(IBinder displayToken, int colorMode); @@ -167,6 +169,7 @@ public class SurfaceControl implements Parcelable { InputWindowHandle handle); private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken, IBinder toToken); + private static native boolean nativeGetProtectedContentSupport(); private final CloseGuard mCloseGuard = CloseGuard.get(); private String mName; @@ -374,6 +377,13 @@ public class SurfaceControl implements Parcelable { */ public static final int WINDOW_TYPE_DONT_SCREENSHOT = 441731; + /** + * internal representation of how to interpret pixel value, used only to convert to ColorSpace. + */ + private static final int INTERNAL_DATASPACE_SRGB = 142671872; + private static final int INTERNAL_DATASPACE_DISPLAY_P3 = 143261696; + private static final int INTERNAL_DATASPACE_SCRGB = 411107328; + private void assignNativeObject(long nativeObject) { if (mNativeObject != 0) { release(); @@ -1516,6 +1526,35 @@ public class SurfaceControl implements Parcelable { } /** + * Returns an array of color spaces with 2 elements. The first color space is the + * default color space and second one is wide color gamut color space. + * @hide + */ + public static ColorSpace[] getCompositionColorSpaces() { + int[] dataspaces = nativeGetCompositionDataspaces(); + ColorSpace srgb = ColorSpace.get(ColorSpace.Named.SRGB); + ColorSpace[] colorSpaces = { srgb, srgb }; + if (dataspaces.length == 2) { + for (int i = 0; i < 2; ++i) { + switch(dataspaces[i]) { + case INTERNAL_DATASPACE_DISPLAY_P3: + colorSpaces[i] = ColorSpace.get(ColorSpace.Named.DISPLAY_P3); + break; + case INTERNAL_DATASPACE_SCRGB: + colorSpaces[i] = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB); + break; + case INTERNAL_DATASPACE_SRGB: + // Other dataspace is not recognized, use SRGB color space instead, + // the default value of the array is already SRGB, thus do nothing. + default: + break; + } + } + } + return colorSpaces; + } + + /** * @hide */ @UnsupportedAppUsage @@ -1730,6 +1769,14 @@ public class SurfaceControl implements Parcelable { } /** + * Returns whether protected content is supported in GPU composition. + * @hide + */ + public static boolean getProtectedContentSupport() { + return nativeGetProtectedContentSupport(); + } + + /** * @hide */ public static class Transaction implements Closeable { diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java index 04e725e64e9c..0b39c3ada0b1 100644 --- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java @@ -68,8 +68,8 @@ final class ChildContentCaptureSession extends ContentCaptureSession { } @Override - void flush() { - mParent.flush(); + void flush(@FlushReason int reason) { + mParent.flush(reason); } @Override @@ -92,6 +92,7 @@ final class ChildContentCaptureSession extends ContentCaptureSession { int flags) { getMainCaptureSession().notifyViewTextChanged(mId, id, text, flags); } + @Override boolean isContentCaptureEnabled() { return getMainCaptureSession().isContentCaptureEnabled(); diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 81b2e01dfbc7..413f1a5a8955 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -24,10 +24,11 @@ import android.annotation.UiThread; import android.content.ComponentName; import android.content.Context; import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; import android.os.RemoteException; import android.util.Log; +import android.view.contentcapture.ContentCaptureSession.FlushReason; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.IResultReceiver; @@ -51,8 +52,6 @@ public final class ContentCaptureManager { private static final String TAG = ContentCaptureManager.class.getSimpleName(); - private static final String BG_THREAD_NAME = "intel_svc_streamer_thread"; - /** * Timeout for calls to system_server. */ @@ -89,24 +88,13 @@ public final class ContentCaptureManager { public ContentCaptureManager(@NonNull Context context, @Nullable IContentCaptureManager service) { mContext = Preconditions.checkNotNull(context, "context cannot be null"); - if (VERBOSE) { - Log.v(TAG, "Constructor for " + context.getPackageName()); - } - mService = service; - // TODO(b/119220549): use an existing bg thread instead... - final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME); - bgThread.start(); - mHandler = Handler.createAsync(bgThread.getLooper()); - } + if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName()); - @NonNull - private static Handler newHandler() { - // TODO(b/119220549): use an existing bg thread instead... - // TODO(b/119220549): use UI Thread directly (as calls are one-way) or an existing bgThread - // or a shared thread / handler held at the Application level - final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME); - bgThread.start(); - return Handler.createAsync(bgThread.getLooper()); + mService = service; + // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we + // do, then we should optimize it to run the tests after the Choreographer finishes the most + // important steps of the frame. + mHandler = Handler.createAsync(Looper.getMainLooper()); } /** @@ -154,8 +142,8 @@ public final class ContentCaptureManager { * * @hide */ - public void flush() { - getMainContentCaptureSession().flush(); + public void flush(@FlushReason int reason) { + getMainContentCaptureSession().flush(reason); } /** diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java index 7bfc5b413615..7fb1fdd2d651 100644 --- a/core/java/android/view/contentcapture/ContentCaptureSession.java +++ b/core/java/android/view/contentcapture/ContentCaptureSession.java @@ -19,6 +19,7 @@ import static android.view.contentcapture.ContentCaptureManager.DEBUG; import static android.view.contentcapture.ContentCaptureManager.VERBOSE; import android.annotation.CallSuper; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.util.DebugUtils; @@ -30,11 +31,14 @@ import android.view.contentcapture.ViewNode.ViewStructureImpl; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.UUID; @@ -125,6 +129,32 @@ public abstract class ContentCaptureSession implements AutoCloseable { private static final int INITIAL_CHILDREN_CAPACITY = 5; + /** @hide */ + public static final int FLUSH_REASON_FULL = 1; + /** @hide */ + public static final int FLUSH_REASON_ACTIVITY_PAUSED = 2; + /** @hide */ + public static final int FLUSH_REASON_ACTIVITY_RESUMED = 3; + /** @hide */ + public static final int FLUSH_REASON_SESSION_STARTED = 4; + /** @hide */ + public static final int FLUSH_REASON_SESSION_FINISHED = 5; + /** @hide */ + public static final int FLUSH_REASON_IDLE_TIMEOUT = 6; + + /** @hide */ + @IntDef(prefix = { "FLUSH_REASON_" }, value = { + FLUSH_REASON_FULL, + FLUSH_REASON_ACTIVITY_PAUSED, + FLUSH_REASON_ACTIVITY_RESUMED, + FLUSH_REASON_SESSION_STARTED, + FLUSH_REASON_SESSION_FINISHED, + FLUSH_REASON_IDLE_TIMEOUT + }) + @Retention(RetentionPolicy.SOURCE) + @interface FlushReason{} + + private final CloseGuard mCloseGuard = CloseGuard.get(); private final Object mLock = new Object(); @@ -212,7 +242,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { /** * Flushes the buffered events to the service. */ - abstract void flush(); + abstract void flush(@FlushReason int reason); /** * Destroys this session, flushing out all pending notifications to the service. @@ -250,7 +280,7 @@ public abstract class ContentCaptureSession implements AutoCloseable { } try { - flush(); + flush(FLUSH_REASON_SESSION_FINISHED); } finally { onDestroy(); } @@ -316,6 +346,31 @@ public abstract class ContentCaptureSession implements AutoCloseable { abstract void internalNotifyViewDisappeared(@NonNull AutofillId id); /** + * Notifies the Content Capture Service that many nodes has been removed from a virtual view + * structure. + * + * <p>Should only be called by views that handle their own virtual view hierarchy. + * + * @param hostId id of the view hosting the virtual hierarchy. + * @param virtualIds ids of the virtual children. + * + * @throws IllegalArgumentException if the {@code hostId} is an autofill id for a virtual view. + * @throws IllegalArgumentException if {@code virtualIds} is empty + */ + public final void notifyViewsDisappeared(@NonNull AutofillId hostId, + @NonNull int[] virtualIds) { + Preconditions.checkArgument(!hostId.isVirtual(), "parent cannot be virtual"); + Preconditions.checkArgument(!ArrayUtils.isEmpty(virtualIds), "virtual ids cannot be empty"); + if (!isContentCaptureEnabled()) return; + + // TODO(b/121050915): create a new VIEWS_DISAPPEARED event type, which could also be used + // to batch delete non-virtual views + for (int id : virtualIds) { + internalNotifyViewDisappeared(new AutofillId(hostId, id, getIdAsInt())); + } + } + + /** * Notifies the Intelligence Service that the value of a text node has been changed. * * @param id of the node. @@ -407,12 +462,31 @@ public abstract class ContentCaptureSession implements AutoCloseable { return mId; } - /** - * @hide - */ + /** @hide */ @NonNull protected static String getStateAsString(int state) { return state + " (" + (state == UNKNWON_STATE ? "UNKNOWN" : DebugUtils.flagsToString(ContentCaptureSession.class, "STATE_", state)) + ")"; } + + /** @hide */ + @NonNull + static String getflushReasonAsString(@FlushReason int reason) { + switch (reason) { + case FLUSH_REASON_FULL: + return "FULL"; + case FLUSH_REASON_ACTIVITY_PAUSED: + return "PAUSED"; + case FLUSH_REASON_ACTIVITY_RESUMED: + return "RESUMED"; + case FLUSH_REASON_SESSION_STARTED: + return "STARTED"; + case FLUSH_REASON_SESSION_FINISHED: + return "FINISHED"; + case FLUSH_REASON_IDLE_TIMEOUT: + return "IDLE"; + default: + return "UNKOWN-" + reason; + } + } } diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java index a3ff8c09aa0c..f0778fa343b1 100644 --- a/core/java/android/view/contentcapture/MainContentCaptureSession.java +++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java @@ -35,7 +35,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.RemoteException; -import android.os.SystemClock; +import android.util.LocalLog; import android.util.Log; import android.util.TimeUtils; import android.view.autofill.AutofillId; @@ -131,6 +131,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // Used just for debugging purposes (on dump) private long mNextFlush; + // TODO(b/121044064): use settings to set size + private final LocalLog mFlushHistory = new LocalLog(10); + /** @hide */ protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler, @Nullable IContentCaptureManager systemServerInterface, @@ -172,8 +175,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } @Override - void flush() { - mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleForceFlush, this)); + void flush(@FlushReason int reason) { + mHandler.sendMessage( + obtainMessage(MainContentCaptureSession::handleForceFlush, this, reason)); } @Override @@ -264,24 +268,25 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) { - if (!handleHasStarted() - && event.getType() != ContentCaptureEvent.TYPE_SESSION_STARTED) { + final int eventType = event.getType(); + if (!handleHasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) { // TODO(b/120494182): comment when this could happen (dialogs?) Log.v(TAG, "handleSendEvent(" + getDebugState() + ", " - + ContentCaptureEvent.getTypeAsString(event.getType()) + + ContentCaptureEvent.getTypeAsString(eventType) + "): session not started yet"); return; } + if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event); if (mEvents == null) { if (VERBOSE) { Log.v(TAG, "handleSendEvent(" + getDebugState() + ", " - + ContentCaptureEvent.getTypeAsString(event.getType()) - + "): cCreating buffer for " + MAX_BUFFER_SIZE + " events"); + + ContentCaptureEvent.getTypeAsString(eventType) + + "): creating buffer for " + MAX_BUFFER_SIZE + " events"); } mEvents = new ArrayList<>(MAX_BUFFER_SIZE); } - if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) { + if (!mEvents.isEmpty() && eventType == TYPE_VIEW_TEXT_CHANGED) { final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1); // TODO(b/121045053): check if flags match @@ -304,7 +309,7 @@ public final class MainContentCaptureSession extends ContentCaptureSession { final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE; if (bufferEvent && !forceFlush) { - handleScheduleFlush(/* checkExisting= */ true); + handleScheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true); return; } @@ -323,15 +328,26 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // when it's launched again return; } + final int flushReason; + switch (eventType) { + case ContentCaptureEvent.TYPE_SESSION_STARTED: + flushReason = FLUSH_REASON_SESSION_STARTED; + break; + case ContentCaptureEvent.TYPE_SESSION_FINISHED: + flushReason = FLUSH_REASON_SESSION_FINISHED; + break; + default: + flushReason = FLUSH_REASON_FULL; + } - handleForceFlush(); + handleForceFlush(flushReason); } private boolean handleHasStarted() { return mState != UNKNWON_STATE; } - private void handleScheduleFlush(boolean checkExisting) { + private void handleScheduleFlush(@FlushReason int reason, boolean checkExisting) { if (!handleHasStarted()) { Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): session not started yet"); return; @@ -340,43 +356,51 @@ public final class MainContentCaptureSession extends ContentCaptureSession { // "Renew" the flush message by removing the previous one mHandler.removeMessages(MSG_FLUSH); } - mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS; + mNextFlush = System.currentTimeMillis() + FLUSHING_FREQUENCY_MS; if (VERBOSE) { - Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): scheduled to flush in " - + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.formatUptime(mNextFlush)); + Log.v(TAG, "handleScheduleFlush(" + getDebugState() + + ", reason=" + getflushReasonAsString(reason) + "): scheduled to flush in " + + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush)); } mHandler.sendMessageDelayed( - obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this) + obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this, reason) .setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS); } - private void handleFlushIfNeeded() { + private void handleFlushIfNeeded(@FlushReason int reason) { if (mEvents.isEmpty()) { if (VERBOSE) Log.v(TAG, "Nothing to flush"); return; } - handleForceFlush(); + handleForceFlush(reason); } - private void handleForceFlush() { + private void handleForceFlush(@FlushReason int reason) { if (mEvents == null) return; if (mDirectServiceInterface == null) { if (VERBOSE) { Log.v(TAG, "handleForceFlush(" + getDebugState() + + ", reason=" + getflushReasonAsString(reason) + "): hold your horses, client not ready: " + mEvents); } if (!mHandler.hasMessages(MSG_FLUSH)) { - handleScheduleFlush(/* checkExisting= */ false); + handleScheduleFlush(reason, /* checkExisting= */ false); } return; } final int numberEvents = mEvents.size(); + final String reasonString = getflushReasonAsString(reason); + if (DEBUG) { + Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState() + + ". Reason: " + reasonString); + } + // Logs reason, size, max size, idle timeout + final String logRecord = "r=" + reasonString + " s=" + numberEvents + + " m=" + MAX_BUFFER_SIZE + " i=" + FLUSHING_FREQUENCY_MS; try { - if (DEBUG) { - Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState()); - } + mFlushHistory.log(logRecord); mHandler.removeMessages(MSG_FLUSH); final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents(); @@ -500,7 +524,6 @@ public final class MainContentCaptureSession extends ContentCaptureSession { @Override void dump(@NonNull String prefix, @NonNull PrintWriter pw) { - pw.print(prefix); pw.print("id: "); pw.println(mId); pw.print(prefix); pw.print("mContext: "); pw.println(mContext); pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId()); if (mSystemServerInterface != null) { @@ -535,8 +558,12 @@ public final class MainContentCaptureSession extends ContentCaptureSession { } pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS); pw.print(prefix); pw.print("next flush: "); - TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println(); + TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw); + pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")"); } + pw.print(prefix); pw.println("flush history:"); + mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println(); + super.dump(prefix, pw); } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 4523d3b2739f..b4d8322c7552 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -21,19 +21,24 @@ import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.LabeledIntent; +import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; import android.database.DataSetObserver; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Environment; import android.os.Handler; @@ -75,6 +80,7 @@ import com.google.android.collect.Lists; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -92,6 +98,15 @@ public class ChooserActivity extends ResolverActivity { private static final boolean DEBUG = false; + /** + * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of + * binding to every ChooserTargetService implementation. + */ + // TODO(b/121287573): Replace with a system flag (setprop?) + private static final boolean USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS = false; + // TODO(b/121287224): Re-evaluate this limit + private static final int SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20; + private static final int QUERY_TARGET_SERVICE_LIMIT = 5; private static final int WATCHDOG_TIMEOUT_MILLIS = 2000; @@ -120,6 +135,7 @@ public class ChooserActivity extends ResolverActivity { private static final int CHOOSER_TARGET_SERVICE_RESULT = 1; private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT = 2; + private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 3; private final Handler mChooserHandler = new Handler() { @Override @@ -158,6 +174,18 @@ public class ChooserActivity extends ResolverActivity { mChooserListAdapter.setShowServiceTargets(true); break; + case SHORTCUT_MANAGER_SHARE_TARGET_RESULT: + if (DEBUG) Log.d(TAG, "SHORTCUT_MANAGER_SHARE_TARGET_RESULT"); + if (isDestroyed()) break; + final ServiceResultInfo resultInfo = (ServiceResultInfo) msg.obj; + if (resultInfo.resultTargets != null) { + mChooserListAdapter.addServiceResults(resultInfo.originalTarget, + resultInfo.resultTargets); + } + sendVoiceChoicesIfNeeded(); + mChooserListAdapter.setShowServiceTargets(true); + break; + default: super.handleMessage(msg); } @@ -552,6 +580,94 @@ public class ChooserActivity extends ResolverActivity { } } + private IntentFilter getTargetIntentFilter() { + try { + final Intent intent = getTargetIntent(); + String dataString = intent.getDataString(); + if (TextUtils.isEmpty(dataString)) { + dataString = intent.getType(); + } + return new IntentFilter(intent.getAction(), dataString); + } catch (Exception e) { + Log.e(TAG, "failed to get target intent filter " + e); + return null; + } + } + + private void queryDirectShareTargets(ChooserListAdapter adapter) { + final IntentFilter filter = getTargetIntentFilter(); + if (filter == null) { + return; + } + + // Need to keep the original DisplayResolveInfos to be able to reconstruct ServiceResultInfo + // and use the old code path. This Ugliness should go away when Sharesheet is refactored. + final List<DisplayResolveInfo> driList = new ArrayList<>(); + int targetsToQuery = 0; + for (int i = 0, n = adapter.getDisplayResolveInfoCount(); i < n; i++) { + final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i); + if (adapter.getScore(dri) == 0) { + // A score of 0 means the app hasn't been used in some time; + // don't query it as it's not likely to be relevant. + continue; + } + driList.add(dri); + targetsToQuery++; + // TODO(b/121287224): Do we need this here? (similar to queryTargetServices) + if (targetsToQuery >= SHARE_TARGET_QUERY_PACKAGE_LIMIT) { + if (DEBUG) { + Log.d(TAG, "queryTargets hit query target limit " + + SHARE_TARGET_QUERY_PACKAGE_LIMIT); + } + break; + } + } + + AsyncTask.execute(() -> { + ShortcutManager sm = (ShortcutManager) getSystemService(Context.SHORTCUT_SERVICE); + List<ShortcutManager.ShareShortcutInfo> resultList = sm.getShareTargets(filter); + + // Match ShareShortcutInfos with DisplayResolveInfos to be able to use the old code path + // for direct share targets. After ShareSheet is refactored we should use the + // ShareShortcutInfos directly. + for (int i = 0; i < driList.size(); i++) { + List<ChooserTarget> chooserTargets = new ArrayList<>(); + for (int j = 0; j < resultList.size(); j++) { + if (driList.get(i).getResolvedComponentName().equals( + resultList.get(j).getTargetComponent())) { + chooserTargets.add(convertToChooserTarget(resultList.get(j))); + } + } + if (chooserTargets.isEmpty()) { + continue; + } + + final Message msg = Message.obtain(); + msg.what = SHORTCUT_MANAGER_SHARE_TARGET_RESULT; + msg.obj = new ServiceResultInfo(driList.get(i), chooserTargets, null); + mChooserHandler.sendMessage(msg); + } + }); + } + + private ChooserTarget convertToChooserTarget(ShortcutManager.ShareShortcutInfo shareShortcut) { + ShortcutInfo shortcutInfo = shareShortcut.getShortcutInfo(); + Bundle extras = new Bundle(); + extras.putString(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId()); + return new ChooserTarget( + // The name of this target. + shortcutInfo.getShortLabel(), + // Don't load the icon until it is selected to be shown + null, + // The ranking score for this target (0.0-1.0); the system will omit items with low + // scores when there are too many Direct Share items. + 0.5f, + // The name of the component to be launched if this target is chosen. + shareShortcut.getTargetComponent().clone(), + // The extra values here will be merged into the Intent when this target is chosen. + extras); + } + private String convertServiceName(String packageName, String serviceName) { if (TextUtils.isEmpty(serviceName)) { return null; @@ -765,9 +881,8 @@ public class ChooserActivity extends ResolverActivity { } } } - final Icon icon = chooserTarget.getIcon(); - // TODO do this in the background - mDisplayIcon = icon != null ? icon.loadDrawable(ChooserActivity.this) : null; + // TODO(b/121287224): do this in the background thread, and only for selected targets + mDisplayIcon = getChooserTargetIconDrawable(chooserTarget); if (sourceInfo != null) { mBackupResolveInfo = null; @@ -791,6 +906,39 @@ public class ChooserActivity extends ResolverActivity { mModifiedScore = other.mModifiedScore; } + /** + * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip + * the call to LauncherApps#getShortcuts(ShortcutQuery). + */ + // TODO(121287224): Refactor code to apply the suggestion above + private Drawable getChooserTargetIconDrawable(ChooserTarget target) { + final Icon icon = target.getIcon(); + if (icon != null) { + return icon.loadDrawable(ChooserActivity.this); + } + if (!USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) { + return null; + } + + Bundle extras = target.getIntentExtras(); + if (extras == null || !extras.containsKey(Intent.EXTRA_SHORTCUT_ID)) { + return null; + } + CharSequence shortcutId = extras.getCharSequence(Intent.EXTRA_SHORTCUT_ID); + LauncherApps launcherApps = (LauncherApps) getSystemService( + Context.LAUNCHER_APPS_SERVICE); + final LauncherApps.ShortcutQuery q = new LauncherApps.ShortcutQuery(); + q.setPackage(target.getComponentName().getPackageName()); + q.setShortcutIds(Arrays.asList(shortcutId.toString())); + q.setQueryFlags(LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC); + final List<ShortcutInfo> shortcuts = launcherApps.getShortcuts(q, getUser()); + if (shortcuts != null && shortcuts.size() > 0) { + return launcherApps.getShortcutIconDrawable(shortcuts.get(0), 0); + } + + return null; + } + public float getModifiedScore() { return mModifiedScore; } @@ -1030,8 +1178,15 @@ public class ChooserActivity extends ResolverActivity { mTargetsNeedPruning = true; } } - if (DEBUG) Log.d(TAG, "List built querying services"); - queryTargetServices(this); + if (USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS) { + if (DEBUG) { + Log.d(TAG, "querying direct share targets from ShortcutManager"); + } + queryDirectShareTargets(this); + } else { + if (DEBUG) Log.d(TAG, "List built querying services"); + queryTargetServices(this); + } } @Override diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java index 594595843ca7..72c67d7ddc08 100644 --- a/core/java/com/android/internal/infra/AbstractRemoteService.java +++ b/core/java/com/android/internal/infra/AbstractRemoteService.java @@ -139,6 +139,14 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I return mDestroyed; } + /** + * Gets the name of the service. + */ + @NonNull + public final ComponentName getComponentName() { + return mComponentName; + } + private void handleOnConnectedStateChangedInternal(boolean connected) { if (connected) { handlePendingRequests(); diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 12a8343b4a5c..67c306413bb2 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -841,6 +841,43 @@ static jint android_media_AudioRecord_get_active_microphones(JNIEnv *env, return jStatus; } +static int android_media_AudioRecord_set_microphone_direction(JNIEnv *env, jobject thiz, + jint direction) { + sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); + if (lpRecorder == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioRecord pointer for setMicrophoneDirection()"); + return (jint)AUDIO_JAVA_ERROR; + } + + jint jStatus = AUDIO_JAVA_SUCCESS; + status_t status = + lpRecorder->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction)); + if (status != NO_ERROR) { + jStatus = nativeToJavaStatus(status); + } + + return jStatus; +} + +static int android_media_AudioRecord_set_microphone_field_dimension(JNIEnv *env, jobject thiz, + jfloat zoom) { + sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); + if (lpRecorder == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", + "Unable to retrieve AudioRecord pointer for setMicrophoneFieldDimension()"); + return (jint)AUDIO_JAVA_ERROR; + } + + jint jStatus = AUDIO_JAVA_SUCCESS; + status_t status = lpRecorder->setMicrophoneFieldDimension(zoom); + if (status != NO_ERROR) { + jStatus = nativeToJavaStatus(status); + } + + return jStatus; +} + // ---------------------------------------------------------------------------- static jint android_media_AudioRecord_get_port_id(JNIEnv *env, jobject thiz) { sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); @@ -896,6 +933,10 @@ static const JNINativeMethod gMethods[] = { {"native_get_active_microphones", "(Ljava/util/ArrayList;)I", (void *)android_media_AudioRecord_get_active_microphones}, {"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id}, + {"native_set_microphone_direction", "(I)I", + (void *)android_media_AudioRecord_set_microphone_direction}, + {"native_set_microphone_field_dimension", "(F)I", + (void *)android_media_AudioRecord_set_microphone_field_dimension}, }; // field names found in android/media/AudioRecord.java diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 10da89227f51..aa10a2f98a7e 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -138,6 +138,7 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent event->getDeviceId(), event->getSource(), event->getDisplayId(), event->getAction(), event->getActionButton(), event->getFlags(), event->getEdgeFlags(), event->getMetaState(), event->getButtonState(), + event->getClassification(), event->getXOffset(), event->getYOffset(), event->getXPrecision(), event->getYPrecision(), event->getDownTime(), event->getHistoricalEventTime(i), diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 9ce6df1832a6..897427fd8787 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -642,6 +642,27 @@ static jint nativeGetActiveColorMode(JNIEnv* env, jclass, jobject tokenObj) { return static_cast<jint>(SurfaceComposerClient::getActiveColorMode(token)); } +static jintArray nativeGetCompositionDataspaces(JNIEnv* env, jclass) { + ui::Dataspace defaultDataspace, wcgDataspace; + ui::PixelFormat defaultPixelFormat, wcgPixelFormat; + if (SurfaceComposerClient::getCompositionPreference(&defaultDataspace, + &defaultPixelFormat, + &wcgDataspace, + &wcgPixelFormat) != NO_ERROR) { + return nullptr; + } + jintArray array = env->NewIntArray(2); + if (array == nullptr) { + jniThrowException(env, "java/lang/OutOfMemoryError", nullptr); + return nullptr; + } + jint* arrayValues = env->GetIntArrayElements(array, 0); + arrayValues[0] = static_cast<jint>(defaultDataspace); + arrayValues[1] = static_cast<jint>(wcgDataspace); + env->ReleaseIntArrayElements(array, arrayValues, 0); + return array; +} + static jboolean nativeSetActiveColorMode(JNIEnv* env, jclass, jobject tokenObj, jint colorMode) { sp<IBinder> token(ibinderForJavaObject(env, tokenObj)); @@ -660,6 +681,10 @@ static void nativeSetDisplayPowerMode(JNIEnv* env, jclass clazz, jobject tokenOb if (t.duration() > 100ms) ALOGD("Excessive delay in setPowerMode()"); } +static jboolean nativeGetProtectedContentSupport(JNIEnv* env, jclass) { + return static_cast<jboolean>(SurfaceComposerClient::getProtectedContentSupport()); +} + static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); status_t err = ctrl->clearLayerFrameStats(); @@ -1016,6 +1041,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetActiveColorMode}, {"nativeSetActiveColorMode", "(Landroid/os/IBinder;I)Z", (void*)nativeSetActiveColorMode}, + {"nativeGetCompositionDataspaces", "()[I", + (void*)nativeGetCompositionDataspaces}, {"nativeGetHdrCapabilities", "(Landroid/os/IBinder;)Landroid/view/Display$HdrCapabilities;", (void*)nativeGetHdrCapabilities }, {"nativeClearContentFrameStats", "(J)Z", @@ -1028,6 +1055,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeGetAnimationFrameStats }, {"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V", (void*)nativeSetDisplayPowerMode }, + {"nativeGetProtectedContentSupport", "()Z", + (void*)nativeGetProtectedContentSupport }, {"nativeDeferTransactionUntil", "(JJLandroid/os/IBinder;J)V", (void*)nativeDeferTransactionUntil }, {"nativeDeferTransactionUntilSurface", "(JJJJ)V", diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index a8e142784397..9e449a20a6f0 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -14,6 +14,15 @@ * limitations under the License. */ +/* + * Disable optimization of this file if we are compiling with the address + * sanitizer. This is a mitigation for b/122921367 and can be removed once the + * bug is fixed. + */ +#if __has_feature(address_sanitizer) +#pragma clang optimize off +#endif + #define LOG_TAG "Zygote" // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 2148273208e5..f68c760a9dbb 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -27,9 +27,569 @@ enum Action { PAGE_VISIBLE = 1; PAGE_HIDE = 2; + // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network + // SUBTYPE: true if connecting to a saved network, false if not + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_WIFI_CONNECT = 135; + + // ACTION: Settings > Wi-Fi > [Long press network] > Forget network + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_WIFI_FORGET = 137; + + // ACTION: Settings > Wi-Fi > Toggle off + // SUBTYPE: true if connected to network before toggle, false if not + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_WIFI_OFF = 138; + + // ACTION: Settings > Wi-Fi > Toggle on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_WIFI_ON = 139; + + // ACTION: Settings > Bluetooth > Overflow > Rename this device + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_BLUETOOTH_RENAME = 161; + + // ACTION: Settings > Bluetooth > Overflow > Show received files + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_BLUETOOTH_FILES = 162; + + // ACTION: DND Settings > Priority only allows > Reminder toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_ALLOW_REMINDERS = 167; + + // ACTION: DND Settings > Priority only allows > Event toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_ALLOW_EVENTS = 168; + + // ACTION: DND Settings > Priority only allows > Messages + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_ALLOW_MESSAGES = 169; + + // ACTION: DND Settings > Priority only allows > Calls + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_ALLOW_CALLS = 170; + + // ACTION: DND Settings > Priority only allows > Repeat callers toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_ALLOW_REPEAT_CALLS = 171; + + // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_DELETE_RULE_OK = 175; + + // ACTION: Settings > More > Airplane mode toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_AIRPLANE_TOGGLE = 177; + + // ACTION: Settings > Data usage > Cellular data toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_CELL_DATA_TOGGLE = 178; + + // ACTION: Settings > Display > When device is rotated + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ROTATION_LOCK = 203; + + // OPEN: Settings > Search > Perform search + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_SEARCH_RESULTS = 226; + + // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_FINGERPRINT_DELETE = 253; + + // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_FINGERPRINT_RENAME = 254; + + // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report + // CATEGORY: SETTINGS + // OS: N + // Interactive bug report initiated from Settings. + ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294; + + // ACTION: Settings -> Developer Options -> Take bug report -> Full report + // CATEGORY: SETTINGS + // OS: N + // Interactive bug report initiated from Settings. + ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295; + + // click on collapsed conditional or clicks expand button + ACTION_SETTINGS_CONDITION_EXPAND = 373; + + // click main area of expanded conditional + ACTION_SETTINGS_CONDITION_CLICK = 375; + + // click a direct button on expanded conditional + ACTION_SETTINGS_CONDITION_BUTTON = 376; + + // Action: user enable / disabled data saver using Settings + // OPEN: Settings -> Data Usage -> Data saver -> On/off toggle + // VALUE: 1 for enabled, 0 for disabled + // CATEGORY: SETTINGS + // OS: N + ACTION_DATA_SAVER_MODE = 394; + + // User whitelisted an app for Data Saver mode; action pass package name of app + // Action: user enable / disabled data saver using Settings + // OPEN: Settings -> Data Usage -> Data saver -> Unrestricted data access > APP toggle turned on + // or + // Settings -> Apps -> APP -> Data usage -> Unrestricted data usage toggle turned on + // VALUE: package name of APP + // CATEGORY: SETTINGS + // OS: N + ACTION_DATA_SAVER_WHITELIST = 395; + + // User blacklisted an app for Data Saver mode; action pass package name of app + // OPEN: Settings -> Apps -> APP -> Data usage -> Background data toggle turned off + // VALUE: package name of APP + // CATEGORY: SETTINGS + // OS: N + ACTION_DATA_SAVER_BLACKLIST = 396; + + // ACTION: Settings -> Storage -> Manage storage -> Click Storage Manager + // SUBTYPE: false is off, true is on + ACTION_TOGGLE_STORAGE_MANAGER = 489; + + // OPEN: Settings > Display -> Ambient Display + // CATEGORY: SETTINGS + ACTION_AMBIENT_DISPLAY = 495; + + // ACTION: Allow Battery optimization for an app + APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764; + + // ACTION: Deny Battery optimization for an app + APP_SPECIAL_PERMISSION_BATTERY_DENY = 765; + + // ACTION: Enable Device Admin app + APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766; + + // ACTION: Disable Device Admin app + APP_SPECIAL_PERMISSION_ADMIN_DENY = 767; + + // ACTION: Allow "Do Not Disturb access" for an app + APP_SPECIAL_PERMISSION_DND_ALLOW = 768; + + // ACTION: Deny "Do Not Disturb access" for an app + APP_SPECIAL_PERMISSION_DND_DENY = 769; + + // ACTION: Allow "Draw over other apps" for an app + APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770; + + // ACTION: Deny "Display over other apps" for an app + APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771; + + // ACTION: Allow "VR helper services" for an app + APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772; + + // ACTION: Deny "VR helper services" for an app + APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773; + + // ACTION: Allow "Modify system settings" for an app + APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774; + + // ACTION: Deny "Modify system settings" for an app + APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775; + + // ACTION: Allow "Notification access" for an app + APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776; + + // ACTION: Deny "Notification access" for an app + APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777; + + // ACTION: "Premium SMS access" for an app - "ask user" option + APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778; + + // ACTION: "Premium SMS access" for an app - "never allow" option + APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779; + + // ACTION: "Premium SMS access" for an app - "always allow" option + APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780; + + // ACTION: Allow "Unrestricted data access" for an app + APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781; + + // ACTION: Deny "Unrestricted data access" for an app + APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782; + + // ACTION: Allow "Usage access" for an app + APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783; + + // ACTION: Deny "Usage access" for an app + APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784; + + // ACTION: "Force stop" action on an app + ACTION_APP_FORCE_STOP = 807; + + // ACTION: Allow "Enable picture-in-picture" for an app + APP_PICTURE_IN_PICTURE_ALLOW = 813; + + // ACTION: Create a Settings shortcut item. + ACTION_SETTINGS_CREATE_SHORTCUT = 829; + + // ACTION: Settings advanced button is expanded + ACTION_SETTINGS_ADVANCED_BUTTON_EXPAND = 834; + + // ACTION: Deny "Enable picture-in-picture" for an app + APP_PICTURE_IN_PICTURE_DENY = 814; + + // ACTION: Settings -> Display -> Theme + ACTION_THEME = 816; + + // ACTION: Settings > About device > Build number + ACTION_SETTINGS_BUILD_NUMBER_PREF = 847; + + // ACTION: Settings > Battery > Menu > Optimization + ACTION_SETTINGS_MENU_BATTERY_OPTIMIZATION = 851; + + // ACTION: Settings > Battery > Menu > Apps Toggle + ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE = 852; + // ACTION: Settings > Any preference is changed ACTION_SETTINGS_PREFERENCE_CHANGE = 853; + // ACTION: Settings > Connected devices > Bluetooth -> Available devices + ACTION_SETTINGS_BLUETOOTH_PAIR = 866; + + // ACTION: Settings > Connected devices > Bluetooth -> Paired devices + ACTION_SETTINGS_BLUETOOTH_CONNECT = 867; + + // ACTION: Settings > Connected devices > Bluetooth -> Connected device + ACTION_SETTINGS_BLUETOOTH_DISCONNECT = 868; + + // ACTION: Settings > Connected devices > Bluetooth -> Error dialog + ACTION_SETTINGS_BLUETOOTH_CONNECT_ERROR = 869; + + // ACTION: Settings > Connected devices > Bluetooth master switch Toggle + ACTION_SETTINGS_MASTER_SWITCH_BLUETOOTH_TOGGLE = 870; + + // ACTION: Settings > App detail > Uninstall + ACTION_SETTINGS_UNINSTALL_APP = 872; + + // ACTION: Settings > App detail > Uninstall Device admin app + ACTION_SETTINGS_UNINSTALL_DEVICE_ADMIN = 873; + + // ACTION: Settings > App detail > Disable app + ACTION_SETTINGS_DISABLE_APP = 874; + + // ACTION: Settings > App detail > Enable app + ACTION_SETTINGS_ENABLE_APP = 875; + + // ACTION: Settings > App detail > Clear data + ACTION_SETTINGS_CLEAR_APP_DATA = 876; + + // ACTION: Settings > App detail > Clear cache + ACTION_SETTINGS_CLEAR_APP_CACHE = 877; + + // ACTION: Logs pressing the "Clear app" button in the app info settings page for an instant + // app. + // VALUE: The package name of the app + ACTION_SETTINGS_CLEAR_INSTANT_APP = 923; + + // OPEN: Assist Gesture training intro in Settings + // CATEGORY: SETTINGS + // OS: O DR + SETTINGS_ASSIST_GESTURE_TRAINING_INTRO = 991; + + // OPEN: Assist Gesture training enrolling in Settings + // CATEGORY: SETTINGS + // OS: O DR + SETTINGS_ASSIST_GESTURE_TRAINING_ENROLLING = 992; + + // OPEN: Assist Gesture training finished in Settings + // CATEGORY: SETTINGS + // OS: O DR + SETTINGS_ASSIST_GESTURE_TRAINING_FINISHED = 993; + + // ACTION: Update default app from Settings + ACTION_SETTINGS_UPDATE_DEFAULT_APP = 1000; + + // ACTION: Settings > Wi-Fi > [Long press network] > Sign in to network + // CATEGORY: SETTINGS + // OS: O DR + ACTION_WIFI_SIGNIN = 1008; + + // ACTION: Settings > Notification Settings > Open application notification + // CATEGORY: SETTINGS + // OS: O DR + ACTION_OPEN_APP_NOTIFICATION_SETTING = 1016; + + // ACTION: Settings > App Info > Open app settings + // CATEGORY: SETTINGS + // OS: O DR + ACTION_OPEN_APP_SETTING = 1017; + + // ACTION: Collect PSD Signals + // CATEGORY: SETTINGS + // OS: O DR + ACTION_PSD_LOADER = 1019; + + // OPEN: Settings > Trampoline Intent > Settings page + // CATEGORY: SETTINGS + // OS: O DR + TRAMPOLINE_SETTINGS_EVENT = 1033; + + // ACTION: Logged when user tries to pair a Bluetooth device without name from Settings app + // CATEGORY: SETTINGS + // OS: O MR + ACTION_SETTINGS_BLUETOOTH_PAIR_DEVICES_WITHOUT_NAMES = 1096; + + // ACTION: Settings > Network & Internet > Mobile network > Network + // CATEGORY: SETTINGS + ACTION_MOBILE_NETWORK_MANUAL_SELECT_NETWORK = 1210; + + // ACTION: DND Settings > Priority only allows > Alarms toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ALLOW_ALARMS = 1226; + + // ACTION: DND Settings > Priority only allows > Media toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ALLOW_MEDIA = 1227; + + // ACTION: A private dns mode been selected by user + // CATEGORY: SETTINGS + // OS: P + ACTION_PRIVATE_DNS_MODE = 1249; + + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name > OK + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK = 1267; + + // OPEN: Settings > Sound > Do Not Disturb > TURN ON NOW/TURN OFF NOW + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_TOGGLE_DND_BUTTON = 1268; + + // ACTION: DND Settings > What to block > full screen intents + // SUBTYPE: false is allowed, true is blocked + // CATEGORY: SETTINGS + // OS: 6.0 + ACTION_ZEN_BLOCK_FULL_SCREEN_INTENTS = 1332; + + // ACTION: DND Settings > What to block + // SUBTYPE: false is allowed, true is blocked + // OS: P + ACTION_ZEN_BLOCK_LIGHT = 1333; + + // ACTION: DND Settings > What to block + // SUBTYPE: false is allowed, true is blocked + // OS: P + ACTION_ZEN_BLOCK_PEEK = 1334; + + // ACTION: DND Settings > What to block + // SUBTYPE: false is allowed, true is blocked + // OS: P + ACTION_ZEN_BLOCK_STATUS = 1335; + + // ACTION: DND Settings > What to block + // SUBTYPE: false is allowed, true is blocked + // OS: P + ACTION_ZEN_BLOCK_BADGE = 1336; + + // ACTION: DND Settings > What to block + // SUBTYPE: false is allowed, true is blocked + // OS: P + ACTION_ZEN_BLOCK_AMBIENT = 1337; + + // ACTION: DND Settings > What to block + // SUBTYPE: false is allowed, true is blocked + // OS: P + ACTION_ZEN_BLOCK_NOTIFICATION_LIST = 1338; + + // ACTION: DND Settings > Priority only allows > System toggle + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ALLOW_SYSTEM = 1340; + + // ACTION: Settings > Battery settings > Battery tip > App restriction tip + // OS: P + ACTION_APP_RESTRICTION_TIP = 1347; + + // ACTION: Settings > Battery settings > Battery tip > High usage tip + // OS: P + ACTION_HIGH_USAGE_TIP = 1348; + + // ACTION: Settings > Battery settings > Battery tip > Summary tip + // OS: P + ACTION_SUMMARY_TIP = 1349; + + // ACTION: Settings > Battery settings > Battery tip > Smart battery tip + // OS: P + ACTION_SMART_BATTERY_TIP = 1350; + + // ACTION: Settings > Battery settings > Battery tip > Early warning tip + // OS: P + ACTION_EARLY_WARNING_TIP = 1351; + + // ACTION: Settings > Battery settings > Battery tip > Low battery tip + // OS: P + ACTION_LOW_BATTERY_TIP = 1352; + + // ACTION: Settings > Battery settings > Battery tip > App restriction list shown + // OS: P + ACTION_APP_RESTRICTION_TIP_LIST = 1353; + + // ACTION: Settings > Battery settings > Battery tip > High usage list shown + // OS: P + ACTION_HIGH_USAGE_TIP_LIST = 1354; + + // ACTION: Settings > Battery settings > Battery tip > Open app restriction page + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_OPEN_APP_RESTRICTION_PAGE = 1361; + + // ACTION: Settings > Battery settings > Battery tip > Restrict app + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_RESTRICT_APP = 1362; + + // ACTION: Settings > Battery settings > Battery tip > Unrestrict app + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_UNRESTRICT_APP = 1363; + + // ACTION: Settings > Battery settings > Battery tip > Open smart battery page + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_OPEN_SMART_BATTERY = 1364; + + // ACTION: Settings > Battery settings > Battery tip > Turn on battery saver + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_TURN_ON_BATTERY_SAVER = 1365; + + // ACTION: Settings > Anomaly receiver > Anomaly received + // CATEGORY: SETTINGS + // OS: P + ACTION_ANOMALY_TRIGGERED = 1367; + + // ACTION: A Settings Slice is requested + // CATEGORY: SETTINGS + // OS: P + ACTION_SETTINGS_SLICE_REQUESTED = 1371; + + // ACTION: A Settings Slice is updated with new value + // CATEGORY: SETTINGS + // OS: P + ACTION_SETTINGS_SLICE_CHANGED = 1372; + + // OPEN: DND onboarding activity > Ok button + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ONBOARDING_OK = 1378; + + // OPEN: DND onboarding activity > Settings link + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ONBOARDING_SETTINGS = 1379; + + // ACTION: Settings > Anomaly receiver > Anomaly ignored, don't show up in battery settings + // CATEGORY: SETTINGS + // OS: P + ACTION_ANOMALY_IGNORED = 1387; + + // ACTION: Settings > Battery settings > Battery tip > Open battery saver page + // CATEGORY: SETTINGS + // OS: P + ACTION_TIP_OPEN_BATTERY_SAVER_PAGE = 1388; + + // ACTION: DND Settings > What to block + // OS: P + ACTION_ZEN_SOUND_ONLY = 1396; + + // ACTION: DND Settings > Notifications + // OS: P + ACTION_ZEN_SOUND_AND_VIS_EFFECTS = 1397; + + // ACTION: DND Settings > Notifications + // OS: P + ACTION_ZEN_SHOW_CUSTOM = 1398; + + // ACTION: DND Settings > Notifications + // OS: P + ACTION_ZEN_CUSTOM = 1399; + + // OPEN: DND onboarding activity > don't update button + // CATEGORY: SETTINGS + // OS: P + ACTION_ZEN_ONBOARDING_KEEP_CURRENT_SETTINGS = 1406; + + // ACTION: Storage initialization wizard initialization choice of external/portable + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_INIT_EXTERNAL = 1407; + + // ACTION: Storage initialization wizard initialization choice of internal/adoptable + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_INIT_INTERNAL = 1408; + + // ACTION: Storage initialization wizard benchmark fast choice of continue + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_BENCHMARK_FAST_CONTINUE = 1409; + + // ACTION: Storage initialization wizard benchmark slow choice of continue + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_BENCHMARK_SLOW_CONTINUE = 1410; + + // ACTION: Storage initialization wizard benchmark slow choice of abort + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_BENCHMARK_SLOW_ABORT = 1411; + + // ACTION: Storage initialization wizard migration choice of now + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_MIGRATE_NOW = 1412; + + // ACTION: Storage initialization wizard migration choice of later + // CATEGORY: SETTINGS + // OS: P + ACTION_STORAGE_MIGRATE_LATER = 1413; + + // OPEN: Settings > Sound > Switch a2dp devices dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_SWITCH_A2DP_DEVICES = 1415; + + + // OPEN: Settings > Sound > Switch hfp devices dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_SWITCH_HFP_DEVICES = 1416; + // ACTION: Tap & Pay -> Default Application Setting -> Use Forground ACTION_NFC_PAYMENT_FOREGROUND_SETTING = 1622; @@ -44,15 +604,1454 @@ enum PageId { // Unknown page. Should not be used in production code. PAGE_UNKNOWN = 0; + // OPEN: Settings > Accessibility + // CATEGORY: SETTINGS + // OS: 6.0 + ACCESSIBILITY = 2; + + // OPEN: Settings > Accessibility > Captions + // CATEGORY: SETTINGS + // OS: 6.0 + ACCESSIBILITY_CAPTION_PROPERTIES = 3; + + // OPEN: Settings > Accessibility > [Service] + // CATEGORY: SETTINGS + // OS: 6.0 + ACCESSIBILITY_SERVICE = 4; + + // OPEN: Settings > Accessibility > Color correction + // CATEGORY: SETTINGS + // OS: 6.0 + ACCESSIBILITY_TOGGLE_DALTONIZER = 5; + + // OPEN: Settings > Accessibility > Accessibility shortcut + // CATEGORY: SETTINGS + // OS: 6.0 + ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6; + + // OPEN: Settings > Accessibility > Magnification gestures (Renamed in O) + // OPEN: Settings > Accessibility > Magnification > Magnify with triple-tap + // OPEN: Settings > Accessibility > Magnification > Magnify with button + // CATEGORY: SETTINGS + // OS: 6.0 + ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7; + + // OPEN: Settings > Accounts + // CATEGORY: SETTINGS + // OS: 6.0 + ACCOUNT = 8; + + // OPEN: Settings > Accounts > [Single Account Sync Settings] + // CATEGORY: SETTINGS + // OS: 6.0 + ACCOUNTS_ACCOUNT_SYNC = 9; + + // OPEN: Settings > Accounts > Add an account + // CATEGORY: SETTINGS + // OS: 6.0 + ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10; + + // OPEN: Settings > Cellular network settings > APNs + // CATEGORY: SETTINGS + // OS: 6.0 + APN = 12; + + // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN] + // CATEGORY: SETTINGS + // OS: 6.0 + APN_EDITOR = 13; + + // OPEN: Settings > Apps > Configure apps > App links > [App] + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_APP_LAUNCH = 17; + + // OPEN: Settings > Internal storage > Apps storage > [App] + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_APP_STORAGE = 19; + + // OPEN: Settings > Apps > [App info] + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_INSTALLED_APP_DETAILS = 20; + + // OPEN: Settings > Memory > App usage > [App Memory usage] + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_PROCESS_STATS_DETAIL = 21; + + // OPEN: Settings > Memory > App usage + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_PROCESS_STATS_UI = 23; + + // OPEN: Choose Bluetooth device (ex: when sharing) + // CATEGORY: SETTINGS + // OS: 6.0 + BLUETOOTH_DEVICE_PICKER = 25; + + // OPEN: Settings > Security > Choose screen lock + // CATEGORY: SETTINGS + // OS: 6.0 + CHOOSE_LOCK_GENERIC = 27; + + // OPEN: Settings > Security > Choose screen lock > Choose your password + // CATEGORY: SETTINGS + // OS: 6.0 + CHOOSE_LOCK_PASSWORD = 28; + + // OPEN: Settings > Security > Choose screen lock > Choose your pattern + // CATEGORY: SETTINGS + // OS: 6.0 + CHOOSE_LOCK_PATTERN = 29; + + // OPEN: Settings > Security > Choose screen lock > Confirm your password + // CATEGORY: SETTINGS + // OS: 6.0 + CONFIRM_LOCK_PASSWORD = 30; + + // OPEN: Settings > Security > Choose screen lock > Confirm your pattern + // CATEGORY: SETTINGS + // OS: 6.0 + CONFIRM_LOCK_PATTERN = 31; + + // OPEN: Settings > Security > Encrypt phone + // CATEGORY: SETTINGS + // OS: 6.0 + CRYPT_KEEPER = 32; + + // OPEN: Settings > Security > Encrypt phone > Confirm + // CATEGORY: SETTINGS + // OS: 6.0 + CRYPT_KEEPER_CONFIRM = 33; + + // OPEN: Settings (Root page) + // CATEGORY: SETTINGS + // OS: 6.0 + DASHBOARD_SUMMARY = 35; + + // OPEN: Settings > Data usage + // CATEGORY: SETTINGS + // OS: 6.0 + DATA_USAGE_SUMMARY = 37; + + // OPEN: Settings > Date & time + // CATEGORY: SETTINGS + // OS: 6.0 + DATE_TIME = 38; + + // OPEN: Settings > Developer options + // CATEGORY: SETTINGS + // OS: 6.0 + DEVELOPMENT = 39; + + // OPEN: Settings > About phone + // CATEGORY: SETTINGS + // OS: 6.0 + DEVICEINFO = 40; + + // OPEN: Settings > Internal storage + // CATEGORY: SETTINGS + // OS: 6.0 + DEVICEINFO_STORAGE = 42; + + // OPEN: Settings > Display + // CATEGORY: SETTINGS + // OS: 6.0 + DISPLAY = 46; + + // OPEN: Settings > Display > Daydream + // CATEGORY: SETTINGS + // OS: 6.0 + DREAM = 47; + + // OPEN: Settings > Security > Screen lock > Secure start-up + // CATEGORY: SETTINGS + // OS: 6.0 + ENCRYPTION = 48; + + // OPEN: Settings > Security > Nexus Imprint + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT = 49; + + // OPEN: Settings > Battery > History details + // CATEGORY: SETTINGS + // OS: 6.0 + FUELGAUGE_BATTERY_HISTORY_DETAIL = 51; + + // OPEN: Settings > Battery > Battery saver + // CATEGORY: SETTINGS + // OS: 6.0 + FUELGAUGE_BATTERY_SAVER = 52; + + // OPEN: Settings > Battery > [App Use details] + // CATEGORY: SETTINGS + // OS: 6.0 + FUELGAUGE_POWER_USAGE_DETAIL = 53; + + // OPEN: Settings > Security > SIM card lock settings + // CATEGORY: SETTINGS + // OS: 6.0 + ICC_LOCK = 56; + + // OPEN: Settings > Language & input > Physical keyboard + // CATEGORY: SETTINGS + // OS: 6.0 + INPUTMETHOD_KEYBOARD = 58; + + // OPEN: Settings > Language & input > Spell checker + // CATEGORY: SETTINGS + // OS: 6.0 + INPUTMETHOD_SPELL_CHECKERS = 59; + + // OBSOLETE + INPUTMETHOD_SUBTYPE_ENABLER = 60; + + // OPEN: Settings > Language & input > Personal dictionary + // CATEGORY: SETTINGS + // OS: 6.0 + INPUTMETHOD_USER_DICTIONARY = 61; + + // OPEN: Settings > Language & input > Add word + // CATEGORY: SETTINGS + // OS: 6.0 + INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62; + + // OPEN: Settings > Location + // CATEGORY: SETTINGS + // OS: 6.0 + LOCATION = 63; + + // OPEN: Settings > Apps + // CATEGORY: SETTINGS + // OS: 6.0 + MANAGE_APPLICATIONS = 65; + + // OPEN: Settings > Backup & reset > Factory data reset + // CATEGORY: SETTINGS + // OS: 6.0 + MASTER_CLEAR = 66; + + // OPEN: Settings > Backup & reset > Factory data reset > Confirm + // CATEGORY: SETTINGS + // OS: 6.0 + MASTER_CLEAR_CONFIRM = 67; + + // OPEN: Settings > More > Android Beam + // CATEGORY: SETTINGS + // OS: 6.0 + NFC_BEAM = 69; + + // OPEN: Settings > Tap & pay + // CATEGORY: SETTINGS + // OS: 6.0 + NFC_PAYMENT = 70; + + // OPEN: Settings > Sound & notification > App notifications > [App] + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_APP_NOTIFICATION = 72; + + // OBSOLETE + NOTIFICATION_REDACTION = 74; + + // OPEN: Settings Widget > Notification log + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_STATION = 75; + + // OPEN: Settings > Sound & notification > Do not disturb + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ZEN_MODE = 76; + + + // OPEN: Print job notification > Print job settings + // CATEGORY: SETTINGS + // OS: 6.0 + PRINT_JOB_SETTINGS = 78; + + // OPEN: Settings > Printing > [Print Service] + // CATEGORY: SETTINGS + // OS: 6.0 + PRINT_SERVICE_SETTINGS = 79; + + // OPEN: Settings > Printing + // CATEGORY: SETTINGS + // OS: 6.0 + PRINT_SETTINGS = 80; + + // OPEN: Settings > Backup & reset + // CATEGORY: SETTINGS + // OS: 6.0 + PRIVACY = 81; + + //OBSOLETE + PROXY_SELECTOR = 82; + + // OPEN: Settings > Backup & reset > Network settings reset + // CATEGORY: SETTINGS + // OS: 6.0 + RESET_NETWORK = 83; + + // OPEN: Settings > Backup & reset > Network settings reset > Confirm + // CATEGORY: SETTINGS + // OS: 6.0 + RESET_NETWORK_CONFIRM = 84; + + // OPEN: Settings > Developer Options > Running Services + // CATEGORY: SETTINGS + // OS: 6.0 + RUNNING_SERVICE_DETAILS = 85; + + // OPEN: Settings > Security > Screen pinning + // CATEGORY: SETTINGS + // OS: 6.0 + SCREEN_PINNING = 86; + + // OPEN: Settings > Security + // CATEGORY: SETTINGS + // OS: 6.0 + SECURITY = 87; + + // OPEN: Settings > SIM cards + // CATEGORY: SETTINGS + // OS: 6.0 + SIM = 88; + + // OBSOLETE + TESTING = 89; + + // OPEN: Settings > More > Tethering & portable hotspot + // CATEGORY: SETTINGS + // OS: 6.0 + TETHER = 90; + + // OPEN: Settings > Security > Trust agents + // CATEGORY: SETTINGS + // OS: 6.0 + TRUST_AGENT = 91; + + // OPEN: Settings > Security > Trusted credentials + // CATEGORY: SETTINGS + // OS: 6.0 + TRUSTED_CREDENTIALS = 92; + + // OPEN: Settings > Language & input > TTS output > [Engine] > Settings + // CATEGORY: SETTINGS + // OS: 6.0 + TTS_ENGINE_SETTINGS = 93; + + // OPEN: Settings > Language & input > Text-to-speech output + // CATEGORY: SETTINGS + // OS: 6.0 + TTS_TEXT_TO_SPEECH = 94; + + // OPEN: Settings > Security > Apps with usage access + // CATEGORY: SETTINGS + // OS: 6.0 + USAGE_ACCESS = 95; + + // OPEN: Settings > Users + // CATEGORY: SETTINGS + // OS: 6.0 + USER = 96; + + // OPEN: Settings > Users > [Restricted profile app & content access] + // CATEGORY: SETTINGS + // OS: 6.0 + USERS_APP_RESTRICTIONS = 97; + + // OPEN: Settings > Users > [User settings] + // CATEGORY: SETTINGS + // OS: 6.0 + USER_DETAILS = 98; + + // OPEN: Settings > More > VPN + // CATEGORY: SETTINGS + // OS: 6.0 + VPN = 100; + + // OPEN: Settings > Display > Choose wallpaper from + // CATEGORY: SETTINGS + // OS: 6.0 + WALLPAPER_TYPE = 101; + + // OPEN: Settings > Display > Cast + // CATEGORY: SETTINGS + // OS: 6.0 + WFD_WIFI_DISPLAY = 102; + + // OPEN: Settings > Wi-Fi + // CATEGORY: SETTINGS + // OS: 6.0 + WIFI = 103; + + // OPEN: Settings > More > Wi-Fi Calling + // CATEGORY: SETTINGS + // OS: 6.0 + WIFI_CALLING = 105; + + // OPEN: Settings > Wi-Fi > Saved networks + // CATEGORY: SETTINGS + // OS: 6.0 + WIFI_SAVED_ACCESS_POINTS = 106; + + // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct + // CATEGORY: SETTINGS + // OS: 6.0 + WIFI_P2P = 109; + + // OPEN: Settings > Apps > Configure apps > App permissions + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_ADVANCED = 130; + + // OPEN: Settings > Location > Scanning + // CATEGORY: SETTINGS + // OS: 6.0 + LOCATION_SCANNING = 131; + + // OPEN: Settings > Sound & notification > App notifications + // CATEGORY: SETTINGS + // OS: 6.0 + MANAGE_APPLICATIONS_NOTIFICATIONS = 133; + + // OPEN: Settings > Sound & notification > DND > Priority only allows + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ZEN_MODE_PRIORITY = 141; + + // OPEN: Settings > Sound & notification > DND > Automatic rules + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ZEN_MODE_AUTOMATION = 142; + + // OPEN: Settings > Sound & notification > DND > [Time based rule] + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144; + + // OPEN: Settings > Apps > Configure apps > App links + // CATEGORY: SETTINGS + // OS: 6.0 + MANAGE_DOMAIN_URLS = 143; + + // OPEN: Settings > Sound & notification > DND > [Event rule] + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ZEN_MODE_EVENT_RULE = 146; + + // OPEN: Settings > Sound & notification > Notification access + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ACCESS = 179; + + // OPEN: Settings > Sound & notification > Do Not Disturb access + // CATEGORY: SETTINGS + // OS: 6.0 + NOTIFICATION_ZEN_MODE_ACCESS = 180; + + // OPEN: Settings > Internal storage > Apps storage + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_STORAGE_APPS = 182; + + // OPEN: Settings > Security > Usage access + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_USAGE_ACCESS_DETAIL = 183; + + // OPEN: Settings > Battery > Battery optimization + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_HIGH_POWER_APPS = 184; + + // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input + // CATEGORY: SETTINGS + // OS: 6.0 + APPLICATIONS_MANAGE_ASSIST = 201; + + // OPEN: Settings > Memory + // CATEGORY: SETTINGS + // OS: 6.0 + PROCESS_STATS_SUMMARY = 202; + + // OPEN: Settings > Apps > Configure Apps > Display over other apps + // CATEGORY: SETTINGS + // OS: 6.0 + SYSTEM_ALERT_WINDOW_APPS = 221; + + // OPEN: Settings > About phone > Legal information + // CATEGORY: SETTINGS + // OS: 6.0 + ABOUT_LEGAL_SETTINGS = 225; + + + // OPEN: Settings > Developer options > Inactive apps + // CATEGORY: SETTINGS + // OS: 6.0 + FUELGAUGE_INACTIVE_APPS = 238; + + // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLLING = 240; + // OPEN: Fingerprint Enroll > Find Sensor + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_FIND_SENSOR = 241; + + // OPEN: Fingerprint Enroll > Fingerprint Enrolled! + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLL_FINISH = 242; + + // OPEN: Fingerprint Enroll introduction + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLL_INTRO = 243; + + // OPEN: Fingerprint Enroll > Let's Start! + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLL_SIDECAR = 245; + + // OPEN: Fingerprint Enroll SUW > Let's Start! + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLLING_SETUP = 246; + + // OPEN: Fingerprint Enroll SUW > Find Sensor + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_FIND_SENSOR_SETUP = 247; + + // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled! + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLL_FINISH_SETUP = 248; + + // OPEN: Fingerprint Enroll SUW introduction + // CATEGORY: SETTINGS + // OS: 6.0 + FINGERPRINT_ENROLL_INTRO_SETUP = 249; + + // OPEN: Settings > Developer Options > Background Check + // CATEGORY: SETTINGS + // OS: N + BACKGROUND_CHECK_SUMMARY = 258; + + // OPEN: Settings > Notifications > [App] > Channel Notifications + // CATEGORY: SETTINGS + // OS: N + NOTIFICATION_TOPIC_NOTIFICATION = 265; + + // OPEN: Settings > Security > User credentials + // CATEGORY: Settings + // OS: N + USER_CREDENTIALS = 285; + + // Logs that the user has edited the enabled VR listeners. + // CATEGORY: SETTINGS + // OS: N + VR_MANAGE_LISTENERS = 334; + + // Settings -> Accessibility -> Click after pointer stops moving + // CATEGORY: SETTINGS + // OS: N + ACCESSIBILITY_TOGGLE_AUTOCLICK = 335; + + // Settings -> Sound + // CATEGORY: SETTINGS + // OS: N + SOUND = 336; + + // Settings -> Notifications -> Gear + // CATEGORY: SETTINGS + // OS: N + CONFIGURE_NOTIFICATION = 337; + + // Settings -> Wi-Fi -> Gear + // CATEGORY: SETTINGS + // OS: N + CONFIGURE_WIFI = 338; + + // Settings -> Display -> Display size + // OS: N + DISPLAY_SCREEN_ZOOM = 339; + + // Settings -> Display -> Font size + // CATEGORY: SETTINGS + // OS: N + ACCESSIBILITY_FONT_SIZE = 340; + + // Settings -> Data usage -> Cellular/Wi-Fi data usage + // CATEGORY: SETTINGS + // OS: N + DATA_USAGE_LIST = 341; + + // Settings -> Data usage -> Billing cycle or DATA_USAGE_LIST -> Gear + // CATEGORY: SETTINGS + // OS: N + BILLING_CYCLE = 342; + + // DATA_USAGE_LIST -> Any item or App info -> Data usage + // CATEGORY: SETTINGS + // OS: N + APP_DATA_USAGE = 343; + + // Settings -> Language & input -> Language + // CATEGORY: SETTINGS + // OS: N + USER_LOCALE_LIST = 344; + + // Settings -> Language & input -> Virtual keyboard + // CATEGORY: SETTINGS + // OS: N + VIRTUAL_KEYBOARDS = 345; + + // Settings -> Language & input -> Physical keyboard + // CATEGORY: SETTINGS + // OS: N + PHYSICAL_KEYBOARDS = 346; + + // Settings -> Language & input -> Virtual keyboard -> Add a virtual keyboard + // CATEGORY: SETTINGS + // OS: N + ENABLE_VIRTUAL_KEYBOARDS = 347; + + // Settings -> Data usage -> Data Saver + // CATEGORY: SETTINGS + // OS: N + DATA_SAVER_SUMMARY = 348; + + // Settings -> Data usage -> Data Saver -> Unrestricted data access + // CATEGORY: SETTINGS + // OS: N + DATA_USAGE_UNRESTRICTED_ACCESS = 349; + + // Settings -> Apps -> Gear -> Special access + SPECIAL_ACCESS = 351; + + // OPEN: SUW Welcome Screen -> Vision Settings + // CATEGORY: SETTINGS + // OS: N + SUW_ACCESSIBILITY = 367; + + // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification gestures (Renamed in O) + // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with triple-tap + // OPEN: SUW Welcome Screen -> Vision Settings -> Magnification -> Magnify with button + // ACTION: New magnification gesture configuration is chosen + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: N + SUW_ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 368; + + // OPEN: SUW Welcome Screen -> Vision Settings -> Font size + // ACTION: New font size is chosen + // SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is largest + // CATEGORY: SETTINGS + // OS: N + SUW_ACCESSIBILITY_FONT_SIZE = 369; + + // OPEN: SUW Welcome Screen -> Vision Settings -> Display size + // ACTION: New display size is chosen + // SUBTYPE: 0 is small, 1 is default, 2 is large, 3 is larger, 4 is largest + // CATEGORY: SETTINGS + // OS: N + SUW_ACCESSIBILITY_DISPLAY_SIZE = 370; + + // OPEN: SUW Welcome Screen -> Vision Settings -> TalkBack + // ACTION: New screen reader configuration is chosen + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: N + SUW_ACCESSIBILITY_TOGGLE_SCREEN_READER = 371; + + // Airplane mode on + SETTINGS_CONDITION_AIRPLANE_MODE = 377; + // AKA Data saver on + SETTINGS_CONDITION_BACKGROUND_DATA = 378; + // Battery saver on + SETTINGS_CONDITION_BATTERY_SAVER = 379; + // Cellular data off + SETTINGS_CONDITION_CELLULAR_DATA = 380; + // Do not disturb on + SETTINGS_CONDITION_DND = 381; + // Hotspot on + SETTINGS_CONDITION_HOTSPOT = 382; + // Work profile off + SETTINGS_CONDITION_WORK_MODE = 383; + + // Settings > Apps > Gear > Special Access > Premium SMS access + PREMIUM_SMS_ACCESS = 388; + + // OPEN: Settings > Accounts > Work profile settings + // CATEGORY: SETTINGS + ACCOUNTS_WORK_PROFILE_SETTINGS = 401; + + // Settings -> Dev options -> Convert to file encryption + CONVERT_FBE = 402; + + // Settings -> Dev options -> Convert to file encryption -> WIPE AND CONVERT... + CONVERT_FBE_CONFIRM = 403; + + // Settings -> Dev options -> Running services + RUNNING_SERVICES = 404; + + // The dialog shown by 3P intent to change current webview implementation. + WEBVIEW_IMPLEMENTATION = 405; + + // OPEN: Settings > Internal storage > Storage manager + // CATEGORY: SETTINGS + STORAGE_MANAGER_SETTINGS = 458; + + // OPEN: Settings -> Gestures + // CATEGORY: SETTINGS + SETTINGS_GESTURES = 459; + + // OPEN: Settings > Display > Night Light + // CATEGORY: SETTINGS + NIGHT_DISPLAY_SETTINGS = 488; + + // Night Light on + SETTINGS_CONDITION_NIGHT_DISPLAY = 492; + + // OPEN: Settings > Language & input > Personal dictionary (single locale) + USER_DICTIONARY_SETTINGS = 514; + + // OPEN: Settings > Date & time > Select time zone + ZONE_PICKER = 515; + + // OPEN: Settings > Security > Device administrators + DEVICE_ADMIN_SETTINGS = 516; + + // OPEN: Settings > Security > Factory Reset Protection dialog + DIALOG_FRP = 528; + + // OPEN: Settings > Custom list preference with confirmation message + DIALOG_CUSTOM_LIST_CONFIRMATION = 529; + + // OPEN: Settings > APN Editor > Error dialog + DIALOG_APN_EDITOR_ERROR = 530; + + // OPEN: Settings > Users > Edit owner info dialog + DIALOG_OWNER_INFO_SETTINGS = 531; + + // OPEN: Settings > Security > Use one lock dialog + DIALOG_UNIFICATION_CONFIRMATION = 532; + + // OPEN: Settings > Security > User Credential + DIALOG_USER_CREDENTIAL = 533; + + // OPEN: Settings > Accounts > Remove account + DIALOG_REMOVE_USER = 534; + + // OPEN: Settings > Accounts > Confirm auto sync dialog + DIALOG_CONFIRM_AUTO_SYNC_CHANGE = 535; + + // OPEN: Settings > Apps > Dialog for running service details + DIALOG_RUNNIGN_SERVICE = 536; + + // OPEN: Settings > Bluetooth > Rename this device + DIALOG_BLUETOOTH_RENAME = 538; + + // OPEN: Settings > Battery optimization > details for app + DIALOG_HIGH_POWER_DETAILS = 540; + + // OPEN: Settings > Keyboard > Show keyboard layout dialog + DIALOG_KEYBOARD_LAYOUT = 541; + + // OPEN: Settings > WIFI Scan permission dialog + DIALOG_WIFI_SCAN_MODE = 543; + + // OPEN: Settings > Wireless > VPN > Config dialog + DIALOG_LEGACY_VPN_CONFIG = 545; + + // OPEN: Settings > Wireless > VPN > Config dialog for app + DIALOG_VPN_APP_CONFIG = 546; + + // OPEN: Settings > Wireless > VPN > Cannot connect dialog + DIALOG_VPN_CANNOT_CONNECT = 547; + + // OPEN: Settings > Wireless > VPN > Replace existing VPN dialog + DIALOG_VPN_REPLACE_EXISTING = 548; + + // OPEN: Settings > Billing cycle > Edit billing cycle dates dialog + DIALOG_BILLING_CYCLE = 549; + + // OPEN: Settings > Billing cycle > Edit data limit/warning dialog + DIALOG_BILLING_BYTE_LIMIT = 550; + + // OPEN: Settings > Billing cycle > turn on data limit dialog + DIALOG_BILLING_CONFIRM_LIMIT = 551; + + // OPEN: Settings > Service > Turn off notification access dialog + DIALOG_DISABLE_NOTIFICATION_ACCESS = 552; + + // OPEN: Settings > Sound > Use personal sound for work profile dialog + DIALOG_UNIFY_SOUND_SETTINGS = 553; + + // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being granted. + DIALOG_ZEN_ACCESS_GRANT = 554; + + // OPEN: Settings > Zen mode > Dialog warning about the zen access privileges being revoked. + DIALOG_ZEN_ACCESS_REVOKE = 555; + + // OPEN: Settings > Zen mode > Dialog that picks time for zen mode. + DIALOG_ZEN_TIMEPICKER = 556; + + // OPEN: Settings > Apps > Dialog that informs user to allow service access for app. + DIALOG_SERVICE_ACCESS_WARNING = 557; + + // OPEN: Settings > Apps > Dialog for app actions (such as force stop/clear data) + DIALOG_APP_INFO_ACTION = 558; + + // OPEN: Settings > Storage > Dialog for forgetting a storage device + DIALOG_VOLUME_FORGET = 559; + + // OPEN: Settings > Storage > Dialog for initializing a volume + DIALOG_VOLUME_INIT = 561; + + // OPEN: Settings > Storage > Dialog for unmounting a volume + DIALOG_VOLUME_UNMOUNT = 562; + + // OPEN: Settings > Storage > Dialog for renaming a volume + DIALOG_VOLUME_RENAME = 563; + + // OPEN: Settings > Storage > Dialog for clear cache + DIALOG_STORAGE_CLEAR_CACHE = 564; + + // OPEN: Settings > Storage > Dialog for system info + DIALOG_STORAGE_SYSTEM_INFO = 565; + + // OPEN: Settings > Storage > Dialog for other info + DIALOG_STORAGE_OTHER_INFO = 566; + + // OPEN: Settings > Storage > Dialog for user info + DIALOG_STORAGE_USER_INFO = 567; + // OPEN: Settings > Add fingerprint > Dialog when user touches fingerprint icon. + DIALOG_FINGERPRINT_ICON_TOUCH = 568; + + // OPEN: Settings > Add fingerprint > Error dialog + DIALOG_FINGERPINT_ERROR = 569; + + // OPEN: Settings > Fingerprint > Rename or delete dialog + DIALOG_FINGERPINT_EDIT = 570; + + // OPEN: Settings > Fingerprint > Dialog for deleting last fingerprint + DIALOG_FINGERPINT_DELETE_LAST = 571; + + // OPEN: SUW > Fingerprint > Dialog to confirm skip fingerprint setup entirely. + DIALOG_FINGERPRINT_SKIP_SETUP = 573; + + // OPEN: Settings > Proxy Selector error dialog + DIALOG_PROXY_SELECTOR_ERROR = 574; + + // OPEN: Settings > Wifi > P2P Settings > Disconnect dialog + DIALOG_WIFI_P2P_DISCONNECT = 575; + + // OPEN: Settings > Wifi > P2P Settings > Cancel connection dialog + DIALOG_WIFI_P2P_CANCEL_CONNECT = 576; + + // OPEN: Settings > Wifi > P2P Settings > Rename dialog + DIALOG_WIFI_P2P_RENAME = 577; + + // OPEN: Settings > Wifi > P2P Settings > Forget group dialog + DIALOG_WIFI_P2P_DELETE_GROUP = 578; + + // OPEN: Settings > APN > Restore default dialog + DIALOG_APN_RESTORE_DEFAULT = 579; + + // OPEN: Settings > Encryption interstitial accessibility warning dialog + DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY = 581; + + // OPEN: Settings > Acessibility > Enable accessiblity service dialog + DIALOG_ACCESSIBILITY_SERVICE_ENABLE = 583; + + // OPEN: Settings > Acessibility > Disable accessiblity service dialog + DIALOG_ACCESSIBILITY_SERVICE_DISABLE = 584; + + // OPEN: Settings > Account > Remove account dialog + DIALOG_ACCOUNT_SYNC_REMOVE = 585; + + // OPEN: Settings > Account > Remove account failed dialog + DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL = 586; + + // OPEN: Settings > Account > Cannot do onetime sync dialog + DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC = 587; + + // OPEN: Settings > Display > Night light > Set start time dialog + DIALOG_NIGHT_DISPLAY_SET_START_TIME = 588; + + // OPEN: Settings > Display > Night light > Set end time dialog + DIALOG_NIGHT_DISPLAY_SET_END_TIME = 589; + + + + // OPEN: Settings > User > Edit info dialog + DIALOG_USER_EDIT = 590; + + // OPEN: Settings > User > Confirm remove dialog + DIALOG_USER_REMOVE = 591; + + // OPEN: Settings > User > Enable calling dialog + DIALOG_USER_ENABLE_CALLING = 592; + + // OPEN: Settings > User > Enable calling and sms dialog + DIALOG_USER_ENABLE_CALLING_AND_SMS = 593; + + // OPEN: Settings > User > Cannot manage device message dialog + DIALOG_USER_CANNOT_MANAGE = 594; + + // OPEN: Settings > User > Add user dialog + DIALOG_USER_ADD = 595; + + // OPEN: Settings > User > Setup user dialog + DIALOG_USER_SETUP = 596; + + // OPEN: Settings > User > Setup profile dialog + DIALOG_USER_SETUP_PROFILE = 597; + + // OPEN: Settings > User > Choose user type dialog + DIALOG_USER_CHOOSE_TYPE = 598; + + // OPEN: Settings > User > Need lockscreen dialog + DIALOG_USER_NEED_LOCKSCREEN = 599; + + // OPEN: Settings > User > Confirm exit guest mode dialog + DIALOG_USER_CONFIRM_EXIT_GUEST = 600; + + // OPEN: Settings > User > Edit user profile dialog + DIALOG_USER_EDIT_PROFILE = 601; + + + // OPEN: Settings > Wifi > Saved AP > Edit dialog + DIALOG_WIFI_SAVED_AP_EDIT = 602; + + // OPEN: Settings > Wifi > Edit AP dialog + DIALOG_WIFI_AP_EDIT = 603; + + // OPEN: Settings > Wifi > Write config to NFC dialog + DIALOG_WIFI_WRITE_NFC = 606; + + // OPEN: Settings > Date > Date picker dialog + DIALOG_DATE_PICKER = 607; + + // OPEN: Settings > Date > Time picker dialog + DIALOG_TIME_PICKER = 608; + + // OPEN: Settings > Wireless > Manage wireless plan dialog + DIALOG_MANAGE_MOBILE_PLAN = 609; + + // OPEN Settings > Bluetooth > Attempt to connect to device that shows dialog + BLUETOOTH_DIALOG_FRAGMENT = 613; + + // OPEN: Settings > Security + // CATEGORY: SETTINGS + // OS: O + ENTERPRISE_PRIVACY_SETTINGS = 628; + + // OPEN: Settings > System + SETTINGS_SYSTEM_CATEGORY = 744; + + // OPEN: Settings > Storage + SETTINGS_STORAGE_CATEGORY = 745; + + // OPEN: Settings > Network & Internet + SETTINGS_NETWORK_CATEGORY = 746; + + // OPEN: Settings > Connected Device + SETTINGS_CONNECTED_DEVICE_CATEGORY = 747; + + // OPEN: Settings > App & Notification + SETTINGS_APP_NOTIF_CATEGORY = 748; + + // OPEN: Settings > System > Language & Region + SETTINGS_LANGUAGE_CATEGORY = 750; + + // OPEN: Settings > System > Input & Gesture > Swipe to notification gesture + SETTINGS_GESTURE_SWIPE_TO_NOTIFICATION = 751; + + // OPEN: Settings > System > Input & Gesture > Double tap power button gesture + SETTINGS_GESTURE_DOUBLE_TAP_POWER = 752; + + // OPEN: Settings > System > Input & Gesture > Pick up gesture + SETTINGS_GESTURE_PICKUP = 753; + + // OPEN: Settings > System > Input & Gesture > Double tap screen gesture + SETTINGS_GESTURE_DOUBLE_TAP_SCREEN = 754; + + // OPEN: Settings > System > Input & Gesture > Double twist gesture + SETTINGS_GESTURE_DOUBLE_TWIST = 755; + + // OPEN: Settings > Apps > Default Apps > Default browser + DEFAULT_BROWSER_PICKER = 785; + // OPEN: Settings > Apps > Default Apps > Default emergency app + DEFAULT_EMERGENCY_APP_PICKER = 786; + + // OPEN: Settings > Apps > Default Apps > Default home + DEFAULT_HOME_PICKER = 787; + + // OPEN: Settings > Apps > Default Apps > Default phone + DEFAULT_PHONE_PICKER = 788; + + // OPEN: Settings > Apps > Default Apps > Default sms + DEFAULT_SMS_PICKER = 789; + + // OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection + DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791; + + // OPEN: Settings > Apps > Default Apps > Default autofill app + DEFAULT_AUTOFILL_PICKER = 792; + + // OPEN: Settings > Apps > Gear > Special Access > Install other apps + // CATEGORY: SETTINGS + // OS: 8.0 + MANAGE_EXTERNAL_SOURCES = 808; + + // Logs that the user has edited the picture-in-picture settings. + // CATEGORY: SETTINGS + SETTINGS_MANAGE_PICTURE_IN_PICTURE = 812; + + // OPEN: SUW Welcome Screen -> Vision Settings -> Select to Speak + // ACTION: Select to Speak configuration is chosen + // SUBTYPE: 0 is off, 1 is on + // CATEGORY: SETTINGS + // OS: N + SUW_ACCESSIBILITY_TOGGLE_SELECT_TO_SPEAK = 817; + + // OPEN: Settings > System > Backup + // CATEGORY: SETTINGS + // OS: O + BACKUP_SETTINGS = 818; + + // OPEN: Settings > Storage > Games + // CATEGORY: SETTINGS + // OS: O + APPLICATIONS_STORAGE_GAMES = 838; + + // OPEN: Settings > Storage > Audio and Music + // CATEGORY: SETTINGS + // OS: O + APPLICATIONS_STORAGE_MUSIC = 839; + + // ACTION: Settings > Storage > Free Up Space to launch Deletion Helper + // CATEGORY: SETTINGS + // OS: O + STORAGE_FREE_UP_SPACE_NOW = 840; + + // ACTION: Settings > Storage > Files to open the File Manager + // CATEGORY: SETTINGS + // OS: O + STORAGE_FILES = 841; + + // OPEN: Settings > Apps > Default Apps > Assist > Default assist + DEFAULT_ASSIST_PICKER = 843; + + // OPEN: Settings > Apps > Default Apps > Assist > Default voice input + DEFAULT_VOICE_INPUT_PICKER = 844; + + // OPEN: Settings > Storage > [Profile] + SETTINGS_STORAGE_PROFILE = 845; + + // OPEN: Settings > Security & screen lock -> Encryption & crendentials + // CATEGORY: SETTINGS + // OS: O + ENCRYPTION_AND_CREDENTIAL = 846; + + // OPEN: Settings > Wi-Fi > Network Details (click on Access Point) + // CATEGORY: SETTINGS + // OS: O + WIFI_NETWORK_DETAILS = 849; + + // OPEN: Settings > Wi-Fi > Wifi Preferences -> Advanced -> Network Scorer + // CATEGORY: SETTINGS + // OS: O + SETTINGS_NETWORK_SCORER = 861; + + // OPEN: Settings > About device > Model > Hardware info dialog + DIALOG_SETTINGS_HARDWARE_INFO = 862; + + // OPEN: Settings > Security & screen lock -> Lock screen preferences + // CATEGORY: SETTINGS + SETTINGS_LOCK_SCREEN_PREFERENCES = 882; + + + // OPEN: Settings -> Display -> When in VR Mode + VR_DISPLAY_PREFERENCE = 921; + + // OPEN: Settings > Accessibility > Magnification + // CATEGORY: SETTINGS + // OS: O + ACCESSIBILITY_SCREEN_MAGNIFICATION_SETTINGS = 922; + + // OPEN: Settings -> System -> Reset options + RESET_DASHBOARD = 924; + + // OPEN: Settings > Security > Nexus Imprint > [Fingerprint] > Delete + // CATEGORY: SETTINGS + // OS: O + FINGERPRINT_REMOVE_SIDECAR = 934; + + // OPEN: Settings > Storage > Movies & TV + // CATEGORY: SETTINGS + // OS: O + APPLICATIONS_STORAGE_MOVIES = 935; + + // OPEN: Settings > Security > Managed Device Info > Apps installed + // CATEGORY: SETTINGS + // OS: O + ENTERPRISE_PRIVACY_INSTALLED_APPS = 938; + + // OPEN: Settings > Security > Managed Device Info > nnn permissions + // CATEGORY: SETTINGS + // OS: O + ENTERPRISE_PRIVACY_PERMISSIONS = 939; + + + // OPEN: Settings > Security > Managed Device Info > Default apps + // CATEGORY: SETTINGS + // OS: O + ENTERPRISE_PRIVACY_DEFAULT_APPS = 940; + + // OPEN: Choose screen lock dialog in Settings + // CATEGORY: SETTINGS + // OS: O DR + SETTINGS_CHOOSE_LOCK_DIALOG = 990; + + // OPEN: Settings > System > Languages & input > Assist gesture + // CATEGORY: SETTINGS + // OS: O DR + SETTINGS_ASSIST_GESTURE = 996; + // OPEN: Settings > Connected Devices > Bluetooth > (click on details link for a paired device) BLUETOOTH_DEVICE_DETAILS = 1009; + // OPEN: Settings > credential pages - prompt for key guard configuration confirmation + CONFIGURE_KEYGUARD_DIALOG = 1010; + + // OPEN: Settings > Network > Tether > Wi-Fi hotspot + WIFI_TETHER_SETTINGS = 1014; + + // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device) + // -> Edit name button. + // CATEGORY: SETTINGS + // OS: O DR + DIALOG_BLUETOOTH_PAIRED_DEVICE_RENAME = 1015; + // OPEN: Settings > Connected devices > Bluetooth > Pair new device + // CATEGORY: SETTINGS + // OS: O DR BLUETOOTH_PAIRING = 1018; + // OPEN: Settings->Connected Devices->Bluetooth->(click on details link for a paired device) + // -> Forget button. + // CATEGORY: SETTINGS + // OS: O DR + DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031; + + // OPEN: Settings > Storage > Photos & Videos + // CATEGORY: SETTINGS + // OS: O MR + APPLICATIONS_STORAGE_PHOTOS = 1092; + + // OPEN: Settings > Display > Colors + // CATEGORY: SETTINGS + // OS: O MR + COLOR_MODE_SETTINGS = 1143; + + // OPEN: Settings > Developer Options > Experiment dashboard + // CATEGORY: SETTINGS + SETTINGS_FEATURE_FLAGS_DASHBOARD = 1217; + + // OPEN: Settings > Notifications > [App] > Topic Notifications + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_CHANNEL_GROUP = 1218; + + // OPEN: Settings > Developer options > Enable > Info dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_ENABLE_DEVELOPMENT_OPTIONS = 1219; + + // OPEN: Settings > Developer options > OEM unlocking > Info dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_ENABLE_OEM_UNLOCKING = 1220; + + // OPEN: Settings > Developer options > USB debugging > Info dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_ENABLE_ADB = 1222; + + // OPEN: Settings > Security > Nexus Imprint > [Fingerprint] + // CATEGORY: SETTINGS + // OS: P + FINGERPRINT_AUTHENTICATE_SIDECAR = 1221; + + // OPEN: Settings > Developer options > Revoke USB debugging authorizations > Info dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_CLEAR_ADB_KEYS = 1223; + + // Open: Settings > Developer options > Quick setting tile config + // CATEGORY: SETTINGS + // OS: P + DEVELOPMENT_QS_TILE_CONFIG = 1224; + + // OPEN: Settings > Developer options > Store logger data persistently on device > Info dialog + // CATEGORY: SETTINGS + // OS: P + DIALOG_LOG_PERSIST = 1225; + + // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling + // CATEGORY: SETTINGS + // OS: P + WIFI_CALLING_FOR_SUB = 1230; + + // Open: Settings > Dev options > Oem unlock > lock it > warning dialog. + // OS: P + DIALOG_OEM_LOCK_INFO = 1238; + + // Open: Settings > System > About phone > IMEI + // CATEGORY: SETTINGS + // OS: P + DIALOG_IMEI_INFO = 1240; + + // OPEN: Settings > System > About Phone > Sim status + // CATEGORY: SETTINGS + // OS: P + DIALOG_SIM_STATUS = 1246; + + // OPEN: Settings > System > About Phone > Android Version + // CATEGORY: SETTINGS + // OS: P + DIALOG_FIRMWARE_VERSION = 1247; + + // OPEN: Settings > Battery(version 2) + // CATEGORY: SETTINGS + // OS: P + FUELGAUGE_POWER_USAGE_SUMMARY_V2 = 1263; + + // OPEN: Settings > Connected devices > Connection preferences + // CATEGORY: SETTINGS + // OS: P + CONNECTION_DEVICE_ADVANCED = 1264; + + // OPEN: Settings > Security > Screen lock gear icon + // CATEGORY: SETTINGS + // OS: P + SCREEN_LOCK_SETTINGS = 1265; + + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Delete rule (trash can icon) + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_DELETE_RULE_DIALOG = 1266; + + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule > Event/Time + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Select rule ("Event") > Rule name + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_RULE_NAME_DIALOG = 1269; + + // OPEN: Settings > Sound > Do Not Disturb > Turn on automatically > Add rule + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_RULE_SELECTION_DIALOG = 1270; + + // OPEN: Settings > Battery > Smart Battery + // CATEGORY: SETTINGS + // OS: P + FUELGAUGE_SMART_BATTERY = 1281; + + // OPEN: Settings > Battery > Smart Battery > Restricted apps + // CATEGORY: SETTINGS + // OS: P + FUELGAUGE_RESTRICTED_APP_DETAILS = 1285; + + // OPEN: Settings > Sound & notification > Do Not Disturb > Turn on now + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_ENABLE_DIALOG = 1286; + + // OPEN: Settings->Connected Devices->USB->(click on details link) + // CATEGORY: SETTINGS + // OS: P + USB_DEVICE_DETAILS = 1291; + + // OPEN: Settings > Accessibility > Vibration + // CATEGORY: SETTINGS + // OS: P + ACCESSIBILITY_VIBRATION = 1292; + + // OPEN: Settings > Accessibility > Vibration > Notification vibration + // CATEGORY: SETTINGS + // OS: P + ACCESSIBILITY_VIBRATION_NOTIFICATION = 1293; + + // OPEN: Settings > Accessibility > Vibration > Touch vibration + // CATEGORY: SETTINGS + // OS: P + ACCESSIBILITY_VIBRATION_TOUCH = 1294; + + // OPEN: Settings->Developer Options->Default USB + // CATEGORY: SETTINGS + // OS: P + USB_DEFAULT = 1312; + + // OPEN: Settings > Battery > Battery tip > Battery tip Dialog + // CATEGORY: SETTINGS + // OS: P + FUELGAUGE_BATTERY_TIP_DIALOG = 1323; + + // OPEN: DND Settings > What to block + // OS: P + ZEN_WHAT_TO_BLOCK = 1339; + + // OPEN: Settings > Sounds > Do Not Disturb > Duration + // CATEGORY: SETTINGS + // OS: P + NOTIFICATION_ZEN_MODE_DURATION_DIALOG = 1341; + + // OPEN: Settings > Date & time > Select time zone -> Region + // CATEGORY: SETTINGS + // OS: P + SETTINGS_ZONE_PICKER_REGION = 1355; + + // OPEN: Settings > Date & time > Select time zone -> Time Zone + // CATEGORY: SETTINGS + // OS: P + SETTINGS_ZONE_PICKER_TIME_ZONE = 1356; + // OPEN: Settings > Date & time > Select time zone -> Select UTC Offset + // CATEGORY: SETTINGS + // OS: P + SETTINGS_ZONE_PICKER_FIXED_OFFSET = 1357; + + // OPEN: Settings > Gestures > Prevent Ringing + // OS: P + SETTINGS_PREVENT_RINGING = 1360; + + // Settings > Condition > Device muted + // CATEGORY: SETTINGS + // OS: P + SETTINGS_CONDITION_DEVICE_MUTED = 1368; + + // Settings > Condition > Device vibrate + // CATEGORY: SETTINGS + // OS: P + SETTINGS_CONDITION_DEVICE_VIBRATE = 1369; + + // OPEN: Settings > Connected devices > previously connected devices + // CATEGORY: SETTINGS + // OS: P + PREVIOUSLY_CONNECTED_DEVICES = 1370; + + // OPEN: Settings > Network & Internet > Wi-Fi > Wi-Fi Preferences > Turn on Wi-Fi automatically + // note: Wifi Scanning must be off for this dialog to show + // CATEGORY: SETTINGS + // OS: P + WIFI_SCANNING_NEEDED_DIALOG = 1373; + + // OPEN: Settings > System > Gestures > Swipe up gesture + // CATEGORY: SETTINGS + // OS: P + SETTINGS_GESTURE_SWIPE_UP = 1374; + + // OPEN: Settings > Storage > Dialog to format a storage volume + // CATEGORY: SETTINGS + // OS: P + DIALOG_VOLUME_FORMAT = 1375; + + // OPEN: DND onboarding activity + // CATEGORY: SETTINGS + // OS: P + SETTINGS_ZEN_ONBOARDING = 1380; + + // OPEN: Settings > Display > Auto brightness + // CATEGORY: SETTINGS + // OS: P + SETTINGS_AUTO_BRIGHTNESS = 1381; + + // OPEN: Settings > Connected Devices > Bluetooth + // CATEGORY: SETTINGS + // OS: P + BLUETOOTH_FRAGMENT = 1390; + + // Screen: DND Settings > Notifications + // OS: P + SETTINGS_ZEN_NOTIFICATIONS = 1400; + + // An event category for slices. + // OPEN: Slice became visible. + // CLOSE: Slice became invisible. + // ACTION: Slice was tapped. + SLICE = 1401; + + // OPEN: Settings -> Developer Options -> Disable Bluetooth A2DP hardware + // offload + // CATEGORY: SETTINGS + // OS: P + DIALOG_BLUETOOTH_DISABLE_A2DP_HW_OFFLOAD = 1441; + // OPEN: Settings homepage SETTINGS_HOMEPAGE = 1502; + // OPEN: Settings > Create shortcut(widget) + // CATEGORY: SETTINGS + // OS: Q + SETTINGS_CREATE_SHORTCUT = 1503; + + // OPEN: Face Enroll introduction + // CATEGORY: SETTINGS + // OS: Q + FACE_ENROLL_INTRO = 1506; + + // OPEN: Face Enroll introduction + // CATEGORY: SETTINGS + // OS: Q + FACE_ENROLL_ENROLLING = 1507; + + // OPEN: Face Enroll introduction + // CATEGORY: SETTINGS + // OS: Q + FACE_ENROLL_FINISHED = 1508; + + // OPEN: Face Enroll sidecar + // CATEGORY: SETTINGS + // OS: Q + FACE_ENROLL_SIDECAR = 1509; + + // OPEN: Settings > Add face > Error dialog + // OS: Q + DIALOG_FACE_ERROR = 1510; + + // OPEN: Settings > Security > Face + // CATEGORY: SETTINGS + // OS: Q + FACE = 1511; + + // OPEN: Settings > Acessibility > HearingAid pairing instructions dialog + // CATEGORY: SETTINGS + // OS: Q + DIALOG_ACCESSIBILITY_HEARINGAID = 1512; + + // OPEN: Settings > Add face + // OS: Q + FACE_ENROLL_PREVIEW = 1554; + + // OPEN: Settings > Network & Internet > Wi-Fi > Add network + // CATEGORY: SETTINGS + // OS: Q + SETTINGS_WIFI_ADD_NETWORK = 1556; + + // OPEN: Settings > System > Input & Gesture > Reach up gesture + // OS: Q + SETTINGS_GESTURE_WAKE_LOCK_SCREEN = 1557; + // OPEN: Settings > System > Input & Gesture > Wake screen SETTINGS_GESTURE_WAKE_SCREEN = 1570; @@ -80,6 +2079,19 @@ enum PageId { // OPEN: Settings > Privacy TOP_LEVEL_PRIVACY = 1587; + // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions > + // Allow apps to override + // CATEGORY: SETTINGS + // OS: Q + NOTIFICATION_ZEN_MODE_OVERRIDING_APPS = 1588; + + + // OPEN: Settings > Sound & notification > Do Not Disturb > See all exceptions > + // Allow apps to override > Choose app + // CATEGORY: SETTINGS + // OS: Q + NOTIFICATION_ZEN_MODE_OVERRIDING_APP = 1589; + // OPEN: Settings > Developer options > Disable > Info dialog DIALOG_DISABLE_DEVELOPMENT_OPTIONS = 1591; @@ -92,6 +2104,69 @@ enum PageId { // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597; + + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_SETTINGS = 1604; + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior > Custom + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_SOUND_SETTINGS = 1605; + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior > Use default Do Not Disturb behavior + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_DEFAULT_SETTINGS = 1606; + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior > Use default Do Not Disturb behavior + // > Notification restriction + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_NOTIFICATION_RESTRICTIONS = 1608; + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior > Use default Do Not Disturb behavior + // > Notification restriction > Custom + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_VIS_EFFECTS = 1609; + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior > Use default Do Not Disturb behavior + // > Notification restriction > Custom > Allow messages + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_MESSAGES = 1610; + + // OPEN: Settings > Sound > Do Not Disturb > Schedules > (Click on system rule) + // > Do Not Disturb behavior > Use default Do Not Disturb behavior + // > Notification restriction > Custom > Allow calls + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_RULE_CALLS = 1611; + + // OPEN: Settings > Sound > Do Not Disturb > Click footer link if custom settings applied + // CATEGORY: SETTINGS + // OS: Q + ZEN_CUSTOM_SETTINGS_DIALOG = 1612; + + // OPEN: Settings > Developer Options > Game Update Packages + // CATEGORY: SETTINGS + // OS: Q + SETTINGS_GUP_DASHBOARD = 1613; + + // OPEN: Settings > Accessibility > Vibration > Ring vibration + // CATEGORY: SETTINGS + // OS: Q + ACCESSIBILITY_VIBRATION_RING = 1620; + // OPEN: Settings > System > Input & Gesture > Skip songs SETTINGS_GESTURE_SKIP = 1624; @@ -100,4 +2175,8 @@ enum PageId { // OPEN: Settings > System > Input & Gesture > Tap to check SETTINGS_GESTURE_TAP_SCREEN = 1626; + + // OPEN: Settings > Network & internet > Click Mobile network to land on a page with a list of + // SIM/eSIM subscriptions. + MOBILE_NETWORK_LIST = 1627; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index cf1f7bb2aac1..f3e32414ee26 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1186,6 +1186,7 @@ <!-- Used for permissions that are associated with activity recognition. TODO(zezeozue). STOPSHIP: Add icon --> <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION" + android:icon="@drawable/perm_group_activity_recognition" android:label="@string/permgrouplab_activityRecognition" android:description="@string/permgroupdesc_activityRecognition" android:request="@string/permgrouprequest_activityRecognition" diff --git a/core/res/res/drawable/perm_group_activity_recognition.xml b/core/res/res/drawable/perm_group_activity_recognition.xml new file mode 100644 index 000000000000..0ade6c674171 --- /dev/null +++ b/core/res/res/drawable/perm_group_activity_recognition.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<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="#000000" + android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 +2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 +0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2 +2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" /> +</vector> diff --git a/core/res/res/drawable/perm_group_sensors.xml b/core/res/res/drawable/perm_group_sensors.xml index ce36c13e1690..e4663d7206fc 100644 --- a/core/res/res/drawable/perm_group_sensors.xml +++ b/core/res/res/drawable/perm_group_sensors.xml @@ -19,11 +19,11 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - - <path - android:fillColor="#000000" - android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 -2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 -0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2 -2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" /> -</vector>
\ No newline at end of file + <path + android:fillColor="#000000" + android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3C4.42,3 2,5.42 2, + 8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5C22, + 5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1l-0.1,-0.1C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5, + 5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5C20, + 11.39 16.86,14.24 12.1,18.55z"/> +</vector> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index aa1364f4a24e..64fdc026cc68 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -618,15 +618,6 @@ <!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds --> <integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer> - <!-- Integer indicating the framework scan interval in milliseconds. This is used in the scenario - where the chipset does not support background scanning (config_wifi_background_scan_suport - is false) to set up a periodic wake up scan so that the device can connect to a new access - point on the move. A value of 0 means no periodic scans will be used in the framework. --> - <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer> - - <!-- Integer indicating the framework no networks periodic scan interval in milliseconds. --> - <integer translatable="false" name="config_wifi_no_network_periodic_scan_interval">300000</integer> - <!-- Integer indicating disconnect mode short scan interval in milliseconds --> <integer translatable="false" name="config_wifi_disconnected_short_scan_interval">15000</integer> @@ -692,6 +683,11 @@ <!-- Wifi driver supports Automatic channel selection (ACS) for softap --> <bool translatable="false" name="config_wifi_softap_acs_supported">false</bool> + <!-- Channel list restriction to Automatic channel selection (ACS) for softap. If the device + doesn't want to restrict channels this should be empty. Value is a comma separated channel + string and/or channel range string like '1-6,11' --> + <string translatable="false" name="config_wifi_softap_acs_supported_channel_list"></string> + <!-- Wifi driver supports IEEE80211AC for softap --> <bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool> @@ -699,6 +695,9 @@ for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) --> <bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool> + <!-- Indicates that connected MAC randomization is supported on this device --> + <bool translatable="false" name="config_wifi_connected_mac_randomization_supported">false</bool> + <!-- Flag indicating whether we should enable the automatic brightness. Software implementation will be used if config_hardware_auto_brightness_available is not set --> <bool name="config_automatic_brightness_available">false</bool> @@ -1892,6 +1891,8 @@ cell broadcasting sms, and MMS. --> <bool name="config_sms_capable">true</bool> + <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use + config_defaultRoleHolders now. --> <!-- Default SMS Application. This will be the default SMS application when the phone first boots. The user can then change the default app to one of their choosing. @@ -1910,6 +1911,12 @@ the behavior will be as though no app was named as an explicit default. --> <string name="default_browser" translatable="false"></string> + <!-- Default role holders. This will be an array of roles and package names of their default + holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". --> + <string-array name="config_defaultRoleHolders" translatable="false"> + <item>android.app.role.SMS: com.android.messaging</item> + </string-array> + <!-- Enable/disable default bluetooth profiles: HSP_AG, ObexObjectPush, Audio, NAP --> <bool name="config_bluetooth_default_profiles">true</bool> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index b3b30e992302..777886a9911c 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2985,6 +2985,11 @@ <public name="system_notification_accent_color" /> </public-group> + <public-group type="array" first-id="0x01070006"> + <!-- @hide @SystemApi --> + <public name="config_defaultRoleHolders" /> + </public-group> + <!-- =============================================================== DO NOT ADD UN-GROUPED ITEMS HERE diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index eb0a7a1d8b10..9317cff054ad 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -325,6 +325,7 @@ <java-symbol type="bool" name="config_forceDefaultOrientation" /> <java-symbol type="bool" name="config_wifi_batched_scan_supported" /> <java-symbol type="bool" name="config_wifi_softap_acs_supported" /> + <java-symbol type="string" name="config_wifi_softap_acs_supported_channel_list" /> <java-symbol type="bool" name="config_wifi_softap_ieee80211ac_supported" /> <java-symbol type="bool" name="config_enableMultiUserUI"/> <java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/> @@ -458,9 +459,7 @@ <java-symbol type="integer" name="config_toastDefaultGravity" /> <java-symbol type="integer" name="config_triplePressOnPowerBehavior" /> <java-symbol type="integer" name="config_shortPressOnSleepBehavior" /> - <java-symbol type="integer" name="config_wifi_framework_scan_interval" /> <java-symbol type="integer" name="config_wifi_supplicant_scan_interval" /> - <java-symbol type="integer" name="config_wifi_no_network_periodic_scan_interval" /> <java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" /> <java-symbol type="integer" name="config_windowOutsetBottom" /> <java-symbol type="integer" name="db_connection_pool_size" /> @@ -1880,6 +1879,7 @@ <java-symbol type="bool" name="config_wifi_dual_band_support" /> <java-symbol type="bool" name="config_wifi_convert_apband_5ghz_to_any" /> <java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" /> + <java-symbol type="bool" name="config_wifi_connected_mac_randomization_supported" /> <java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" /> <java-symbol type="bool" name="config_wimaxEnabled" /> <java-symbol type="bool" name="show_ongoing_ime_switcher" /> diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java index a2f0eba0b831..05c0df7c9a5f 100644 --- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java +++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java @@ -97,6 +97,22 @@ public class ContentCaptureSessionTest { assertThat(structure.getAutofillId()).isEqualTo(childId); } + @Test + public void testNotifyViewsDisappeared_invalid() { + // Null parent + assertThrows(NullPointerException.class, + () -> mSession1.notifyViewsDisappeared(null, new int[] {42})); + // Null child + assertThrows(IllegalArgumentException.class, + () -> mSession1.notifyViewsDisappeared(new AutofillId(42), null)); + // Empty child + assertThrows(IllegalArgumentException.class, + () -> mSession1.notifyViewsDisappeared(new AutofillId(42), new int[] {})); + // Virtual parent + assertThrows(IllegalArgumentException.class, + () -> mSession1.notifyViewsDisappeared(new AutofillId(42, 108), new int[] {666})); + } + // Cannot use @Spy because we need to pass the session id on constructor private class MyContentCaptureSession extends ContentCaptureSession { @@ -115,7 +131,7 @@ public class ContentCaptureSessionTest { } @Override - void flush() { + void flush(int reason) { throw new UnsupportedOperationException("should not have been called"); } diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java new file mode 100644 index 000000000000..c03d1f37ffa7 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderEndToEndTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import android.os.SystemClock; +import android.support.test.filters.LargeTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.internal.os.KernelCpuThreadReader.ProcessCpuUsage; +import com.android.internal.os.KernelCpuThreadReader.ThreadCpuUsage; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.OptionalDouble; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +/** + * End to end test for {@link KernelCpuThreadReader} that checks the accuracy of the reported times + * by spawning threads that do a predictable amount of work + */ +@RunWith(AndroidJUnit4.class) +@LargeTest +public class KernelCpuThreadReaderEndToEndTest { + + private static final int TIMED_NUM_SAMPLES = 5; + private static final int TIMED_START_MILLIS = 500; + private static final int TIMED_END_MILLIS = 2000; + private static final int TIMED_INCREMENT_MILLIS = 500; + private static final int TIMED_COMPARISON_DELTA_MILLIS = 200; + + private static final int ITERATIVE_NUM_SAMPLES = 100; + private static final long ITERATIVE_LOW_ITERATIONS = (long) 1e8; + private static final long ITERATIVE_HIGH_ITERATIONS = (long) 2e8; + private static final double ITERATIONS_COMPARISONS_DELTA = 0.25; + + /** + * Test that when we busy-wait for the thread-local time to reach N seconds, the time reported + * is also N seconds. Takes ~10s. + */ + @Test + public void testTimedWork() throws InterruptedException { + for (int millis = TIMED_START_MILLIS; + millis <= TIMED_END_MILLIS; + millis += TIMED_INCREMENT_MILLIS) { + final Duration targetDuration = Duration.ofMillis(millis); + final Runnable work = timedWork(targetDuration); + Duration resultDuration = getAverageWorkTime( + work, String.format("timed%dms", millis), TIMED_NUM_SAMPLES); + assertEquals( + "Time worked according to currentThreadTimeMillis doesn't match " + + "KernelCpuThreadReader", + targetDuration.toMillis(), resultDuration.toMillis(), + TIMED_COMPARISON_DELTA_MILLIS); + } + } + + /** + * Test that when we scale up the amount of work by N, the time reported also scales by N. Takes + * ~15s. + */ + @Test + public void testIterativeWork() throws InterruptedException { + final Runnable lowAmountWork = iterativeWork(ITERATIVE_LOW_ITERATIONS); + final Runnable highAmountWork = iterativeWork(ITERATIVE_HIGH_ITERATIONS); + final Duration lowResultDuration = + getAverageWorkTime(lowAmountWork, "iterlow", ITERATIVE_NUM_SAMPLES); + final Duration highResultDuration = + getAverageWorkTime(highAmountWork, "iterhigh", ITERATIVE_NUM_SAMPLES); + assertEquals( + "Work scale and CPU time scale do not match", + ((double) ITERATIVE_HIGH_ITERATIONS) / ((double) ITERATIVE_LOW_ITERATIONS), + ((double) highResultDuration.toMillis()) / ((double) lowResultDuration.toMillis()), + ITERATIONS_COMPARISONS_DELTA); + } + + /** + * Run some work {@code numSamples} times, and take the average CPU duration used for that work + * according to {@link KernelCpuThreadReader} + */ + private Duration getAverageWorkTime( + Runnable work, String tag, int numSamples) throws InterruptedException { + // Count down every time a thread finishes work, so that we can wait for work to complete + final CountDownLatch workFinishedLatch = new CountDownLatch(numSamples); + // Count down once when threads can terminate (after we get them from + // `KernelCpuThreadReader`) + final CountDownLatch threadFinishedLatch = new CountDownLatch(1); + + // Start `NUM_SAMPLE` threads to do the work + for (int i = 0; i < numSamples; i++) { + final String threadName = String.format("%s%d", tag, i); + // Check the thread name, as we rely on it later to identify threads + assertTrue("Max name length for linux threads is 15", threadName.length() <= 15); + doWork(work, threadName, workFinishedLatch, threadFinishedLatch); + } + + // Wait for threads to finish + workFinishedLatch.await(); + + // Get thread data from KernelCpuThreadReader + final KernelCpuThreadReader kernelCpuThreadReader = KernelCpuThreadReader.create(); + assertNotNull(kernelCpuThreadReader); + final ProcessCpuUsage currentProcessCpuUsage = + kernelCpuThreadReader.getCurrentProcessCpuUsage(); + + // Threads can terminate, as we've finished crawling them from /proc + threadFinishedLatch.countDown(); + + // Check that we've got times for every thread we spawned + final List<ThreadCpuUsage> threadCpuUsages = currentProcessCpuUsage.threadCpuUsages + .stream() + .filter((thread) -> thread.threadName.startsWith(tag)) + .collect(Collectors.toList()); + assertEquals( + "Incorrect number of threads returned by KernelCpuThreadReader", + numSamples, threadCpuUsages.size()); + + // Calculate the average time spent working + final OptionalDouble averageWorkTimeMillis = threadCpuUsages.stream() + .mapToDouble((t) -> Arrays.stream(t.usageTimesMillis).sum()) + .average(); + assertTrue(averageWorkTimeMillis.isPresent()); + return Duration.ofMillis((long) averageWorkTimeMillis.getAsDouble()); + } + + /** + * Work that lasts {@code duration} according to {@link SystemClock#currentThreadTimeMillis()} + */ + private Runnable timedWork(Duration duration) { + return () -> { + // Busy loop until `duration` has elapsed for the thread timer + final long startTimeMillis = SystemClock.currentThreadTimeMillis(); + final long durationMillis = duration.toMillis(); + while (true) { + final long elapsedMillis = SystemClock.currentThreadTimeMillis() - startTimeMillis; + if (elapsedMillis >= durationMillis) { + break; + } + } + }; + } + + /** + * Work that iterates {@code iterations} times + */ + private Runnable iterativeWork(long iterations) { + Consumer<Long> empty = (i) -> { + }; + return () -> { + long count = 0; + for (long i = 0; i < iterations; i++) { + // Alternate branching to reduce effect of branch prediction + if (i % 2 == 0) { + count++; + } + } + // Call empty function with value to avoid loop getting optimized away + empty.accept(count); + }; + } + + /** + * Perform some work in another thread + * + * @param work the work to perform + * @param threadName the name of the spawned thread + * @param workFinishedLatch latch to register that the work has been completed + * @param threadFinishedLatch latch to pause termination of the thread until the latch is + * decremented + */ + private void doWork( + Runnable work, + String threadName, + CountDownLatch workFinishedLatch, + CountDownLatch threadFinishedLatch) { + Runnable workWrapped = () -> { + // Do the work + work.run(); + // Notify that the work is finished + workFinishedLatch.countDown(); + // Wait until `threadFinishLatch` has been released in order to keep the thread alive so + // we can see it in `proc` filesystem + try { + threadFinishedLatch.await(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }; + new Thread(workWrapped, threadName).start(); + } +} diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 6b9ebd3e8d12..1655e89a9b97 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1643,10 +1643,6 @@ struct ResTable_overlayable_policy_header // The overlay must reside of the product partition or must have existed on the product // partition before an upgrade to overlay these resources. POLICY_PRODUCT_PARTITION = 0x00000008, - - // The overlay must reside of the product services partition or must have existed on the product - // services partition before an upgrade to overlay these resources. - POLICY_PRODUCT_SERVICES_PARTITION = 0x00000010, }; uint32_t policy_flags; diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index 2e386a083185..b8d3c6bf92fb 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -312,7 +312,6 @@ TEST(LoadedArscTest, LoadOverlayable) { EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION - | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable4); diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk Binary files differindex 863474794d00..047e6afde86b 100644 --- a/libs/androidfw/tests/data/overlayable/overlayable.apk +++ b/libs/androidfw/tests/data/overlayable/overlayable.apk diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml index dba7b08628f1..fcdbe94466c1 100644 --- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml +++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml @@ -32,9 +32,9 @@ </overlayable> <overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable"> - <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of + <!-- Any overlay on the vendor or product partition can overlay the value of @string/overlayable3 --> - <policy type="product_services|vendor|product"> + <policy type="vendor|product"> <item type="string" name="overlayable3" /> </policy> </overlayable> diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index b4f19c99c6fe..d742cc34b57e 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -255,7 +255,7 @@ void PointerController::setPresentation(Presentation presentation) { if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) { mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, - &mLocked.animationResources); + &mLocked.animationResources, mLocked.viewport.displayId); } if (mLocked.presentation != presentation) { @@ -727,14 +727,14 @@ void PointerController::fadeOutAndReleaseAllSpotsLocked() { } void PointerController::loadResourcesLocked() REQUIRES(mLock) { - mPolicy->loadPointerResources(&mResources); + mPolicy->loadPointerResources(&mResources, mLocked.viewport.displayId); if (mLocked.presentation == PRESENTATION_POINTER) { mLocked.additionalMouseResources.clear(); mLocked.animationResources.clear(); - mPolicy->loadPointerIcon(&mLocked.pointerIcon); + mPolicy->loadPointerIcon(&mLocked.pointerIcon, mLocked.viewport.displayId); mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, - &mLocked.animationResources); + &mLocked.animationResources, mLocked.viewport.displayId); } mLocked.pointerIconChanged = true; diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index a32cc42a3342..be057867890d 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -62,10 +62,10 @@ protected: virtual ~PointerControllerPolicyInterface() { } public: - virtual void loadPointerIcon(SpriteIcon* icon) = 0; - virtual void loadPointerResources(PointerResources* outResources) = 0; + virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId) = 0; + virtual void loadPointerResources(PointerResources* outResources, int32_t displayId) = 0; virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, - std::map<int32_t, PointerAnimation>* outAnimationResources) = 0; + std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) = 0; virtual int32_t getDefaultPointerIconId() = 0; virtual int32_t getCustomPointerIconId() = 0; }; diff --git a/media/Android.bp b/media/Android.bp index d5da6f266952..8ebc91a06f7a 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -1,4 +1,21 @@ java_library { + name: "media1", + + srcs: [ + ":media1-srcs", + ], + + sdk_version: "system_current", +} + +filegroup { + name: "media1-srcs", + srcs: [ + "java/android/media/session/MediaSessionProviderService.java", + ], +} + +java_library { // TODO: include media2.jar in the media apex and add it to the bootclasspath. name: "media2", diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 33f81f1db69c..92afe7ede8f2 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -61,7 +61,8 @@ import java.util.concurrent.Executor; * been read yet. Data should be read from the audio hardware in chunks of sizes inferior to * the total recording buffer size. */ -public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient +public class AudioRecord implements AudioRouting, MicrophoneDirection, + AudioRecordingMonitor, AudioRecordingMonitorClient { //--------------------------------------------------------- // Constants @@ -1657,7 +1658,6 @@ public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRe return activeMicrophones; } - //-------------------------------------------------------------------------- // Implementation of AudioRecordingMonitor interface //-------------------- @@ -1707,6 +1707,33 @@ public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRe return native_getPortId(); } + //-------------------------------------------------------------------------- + // MicrophoneDirection + //-------------------- + /** + * Specifies the logical microphone (for processing). + * + * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*) + * @return retval OK if the call is successful, an error code otherwise. + * @hide + */ + public int setMicrophoneDirection(int direction) { + return native_set_microphone_direction(direction); + } + + /** + * Specifies the zoom factor (i.e. the field dimension) for the selected microphone + * (for processing). The selected microphone is determined by the use-case for the stream. + * + * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle), + * though 0 (no zoom) to 1 (maximum zoom). + * @return retval OK if the call is successful, an error code otherwise. + * @hide + */ + public int setMicrophoneFieldDimension(float zoom) { + return native_set_microphone_field_dimension(zoom); + } + //--------------------------------------------------------- // Interface definitions //-------------------- @@ -1860,6 +1887,9 @@ public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRe private native int native_getPortId(); + private native int native_set_microphone_direction(int direction); + private native int native_set_microphone_field_dimension(float zoom); + //--------------------------------------------------------- // Utility methods //------------------ diff --git a/media/java/android/media/Controller2Link.java b/media/java/android/media/Controller2Link.java index a62db5f1fb20..d11f7769ee5e 100644 --- a/media/java/android/media/Controller2Link.java +++ b/media/java/android/media/Controller2Link.java @@ -16,6 +16,7 @@ package android.media; +import android.os.Binder; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -102,6 +103,15 @@ public final class Controller2Link implements Parcelable { } } + /** Interface method for IMediaController2.notifyPlaybackActiveChanged */ + public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) { + try { + mIController.notifyPlaybackActiveChanged(seq, playbackActive); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** Interface method for IMediaController2.sendSessionCommand */ public void sendSessionCommand(int seq, Session2Command command, Bundle args, ResultReceiver resultReceiver) { @@ -135,6 +145,11 @@ public final class Controller2Link implements Parcelable { mController.onDisconnected(seq); } + /** Stub implementation for IMediaController2.notifyPlaybackActiveChanged */ + public void onPlaybackActiveChanged(int seq, boolean playbackActive) { + mController.onPlaybackActiveChanged(seq, playbackActive); + } + /** Stub implementation for IMediaController2.sendSessionCommand */ public void onSessionCommand(int seq, Session2Command command, Bundle args, ResultReceiver resultReceiver) { @@ -149,23 +164,53 @@ public final class Controller2Link implements Parcelable { private class Controller2Stub extends IMediaController2.Stub { @Override public void notifyConnected(int seq, Bundle connectionResult) { - Controller2Link.this.onConnected(seq, connectionResult); + final long token = Binder.clearCallingIdentity(); + try { + Controller2Link.this.onConnected(seq, connectionResult); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void notifyDisconnected(int seq) { - Controller2Link.this.onDisconnected(seq); + final long token = Binder.clearCallingIdentity(); + try { + Controller2Link.this.onDisconnected(seq); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + @Override + public void notifyPlaybackActiveChanged(int seq, boolean playbackActive) { + final long token = Binder.clearCallingIdentity(); + try { + Controller2Link.this.onPlaybackActiveChanged(seq, playbackActive); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void sendSessionCommand(int seq, Session2Command command, Bundle args, ResultReceiver resultReceiver) { - Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver); + final long token = Binder.clearCallingIdentity(); + try { + Controller2Link.this.onSessionCommand(seq, command, args, resultReceiver); + } finally { + Binder.restoreCallingIdentity(token); + } } @Override public void cancelSessionCommand(int seq) { - Controller2Link.this.onCancelCommand(seq); + final long token = Binder.clearCallingIdentity(); + try { + Controller2Link.this.onCancelCommand(seq); + } finally { + Binder.restoreCallingIdentity(token); + } } } } diff --git a/media/java/android/media/IMediaController2.aidl b/media/java/android/media/IMediaController2.aidl index ca5394f504cb..42c6e70529ec 100644 --- a/media/java/android/media/IMediaController2.aidl +++ b/media/java/android/media/IMediaController2.aidl @@ -31,8 +31,9 @@ import android.media.Session2Command; oneway interface IMediaController2 { void notifyConnected(int seq, in Bundle connectionResult) = 0; void notifyDisconnected(int seq) = 1; + void notifyPlaybackActiveChanged(int seq, boolean playbackActive) = 2; void sendSessionCommand(int seq, in Session2Command command, in Bundle args, - in ResultReceiver resultReceiver) = 2; - void cancelSessionCommand(int seq) = 3; - // Next Id : 4 + in ResultReceiver resultReceiver) = 3; + void cancelSessionCommand(int seq) = 4; + // Next Id : 5 } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index bc9500ddb3b7..f756658b4fa8 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -1829,9 +1829,14 @@ final public class MediaCodec { mBufferLock = new Object(); + // save name used at creation + mNameAtCreation = nameIsType ? null : name; + native_setup(name, nameIsType, encoder); } + private String mNameAtCreation; + @Override protected void finalize() { native_finalize(); @@ -3317,12 +3322,36 @@ final public class MediaCodec { private native void native_setAudioPresentation(int presentationId, int programId); /** - * Get the component name. If the codec was created by createDecoderByType - * or createEncoderByType, what component is chosen is not known beforehand. + * Retrieve the codec name. + * + * If the codec was created by createDecoderByType or createEncoderByType, what component is + * chosen is not known beforehand. This method returns the name of the codec that was + * selected by the platform. + * + * <strong>Note:</strong> Implementations may provide multiple aliases (codec + * names) for the same underlying codec, any of which can be used to instantiate the same + * underlying codec in {@link MediaCodec#createByCodecName}. This method returns the + * name used to create the codec in this case. + * + * @throws IllegalStateException if in the Released state. + */ + @NonNull + public final String getName() { + // get canonical name to handle exception + String canonicalName = getCanonicalName(); + return mNameAtCreation != null ? mNameAtCreation : canonicalName; + } + + /** + * Retrieve the underlying codec name. + * + * This method is similar to {@link #getName}, except that it returns the underlying component + * name even if an alias was used to create this MediaCodec object by name, + * * @throws IllegalStateException if in the Released state. */ @NonNull - public native final String getName(); + public native final String getCanonicalName(); /** * Return Metrics data about the current codec instance. diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 10a1e3a72225..751d57bbdc81 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -32,8 +32,10 @@ import android.util.Size; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Vector; /** * Provides information about a given media codec available on the device. You can @@ -61,15 +63,25 @@ import java.util.Set; * */ public final class MediaCodecInfo { - private boolean mIsEncoder; + private static final String TAG = "MediaCodecInfo"; + + private static final int FLAG_IS_ENCODER = (1 << 0); + private static final int FLAG_IS_VENDOR = (1 << 1); + private static final int FLAG_IS_SOFTWARE_ONLY = (1 << 2); + private static final int FLAG_IS_HARDWARE_ACCELERATED = (1 << 3); + + private int mFlags; private String mName; + private String mCanonicalName; private Map<String, CodecCapabilities> mCaps; /* package private */ MediaCodecInfo( - String name, boolean isEncoder, CodecCapabilities[] caps) { + String name, String canonicalName, int flags, CodecCapabilities[] caps) { mName = name; - mIsEncoder = isEncoder; + mCanonicalName = canonicalName; + mFlags = flags; mCaps = new HashMap<String, CodecCapabilities>(); + for (CodecCapabilities c: caps) { mCaps.put(c.getMimeType(), c); } @@ -77,16 +89,69 @@ public final class MediaCodecInfo { /** * Retrieve the codec name. + * + * <strong>Note:</strong> Implementations may provide multiple aliases (codec + * names) for the same underlying codec, any of which can be used to instantiate the same + * underlying codec in {@link MediaCodec#createByCodecName}. + * + * Applications targeting SDK < {@link android.os.Build.VERSION_CODES#Q}, cannot determine if + * the multiple codec names listed in MediaCodecList are in-fact for the same codec. */ + @NonNull public final String getName() { return mName; } /** + * Retrieve the underlying codec name. + * + * Device implementations may provide multiple aliases (codec names) for the same underlying + * codec to maintain backward app compatibility. This method returns the name of the underlying + * codec name, which must not be another alias. For non-aliases this is always the name of the + * codec. + */ + @NonNull + public final String getCanonicalName() { + return mCanonicalName; + } + + /** + * Query if the codec is an alias for another underlying codec. + */ + public final boolean isAlias() { + return !mName.equals(mCanonicalName); + } + + /** * Query if the codec is an encoder. */ public final boolean isEncoder() { - return mIsEncoder; + return (mFlags & FLAG_IS_ENCODER) != 0; + } + + /** + * Query if the codec is provided by the Android platform (false) or the device manufacturer + * (true). + */ + public final boolean isVendor() { + return (mFlags & FLAG_IS_VENDOR) != 0; + } + + /** + * Query if the codec is software only. Software-only codecs are more secure as they run in + * a tighter security sandbox. On the other hand, software-only codecs do not provide any + * performance guarantees. + */ + public final boolean isSoftwareOnly() { + return (mFlags & FLAG_IS_SOFTWARE_ONLY) != 0; + } + + /** + * Query if the codec is hardware accelerated. This attribute is provided by the device + * manufacturer. Note that it cannot be tested for correctness. + */ + public final boolean isHardwareAccelerated() { + return (mFlags & FLAG_IS_HARDWARE_ACCELERATED) != 0; } /** @@ -163,7 +228,7 @@ public final class MediaCodecInfo { // such as B-frame support, arithmetic coding... public CodecProfileLevel[] profileLevels; // NOTE this array is modifiable by user - // from OMX_COLOR_FORMATTYPE + // from MediaCodecConstants /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ public static final int COLOR_FormatMonochrome = 1; /** @deprecated Use {@link #COLOR_Format24bitBGR888}. */ @@ -344,7 +409,7 @@ public final class MediaCodecInfo { /** @deprecated Use {@link #COLOR_FormatYUV420Flexible}. */ public static final int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100; // COLOR_FormatSurface indicates that the data will be a GraphicBuffer metadata reference. - // In OMX this is called OMX_COLOR_FormatAndroidOpaque. + // Note: in OMX this is called OMX_COLOR_FormatAndroidOpaque. public static final int COLOR_FormatSurface = 0x7F000789; /** @@ -435,8 +500,7 @@ public final class MediaCodecInfo { public static final int COLOR_QCOM_FormatYUV420SemiPlanar = 0x7fa30c00; /** - * Defined in the OpenMAX IL specs, color format values are drawn from - * OMX_COLOR_FORMATTYPE. + * The color format for the media. This is one of the color constants defined in this class. */ public int[] colorFormats; // NOTE this array is modifiable by user @@ -462,6 +526,26 @@ public final class MediaCodecInfo { public static final String FEATURE_TunneledPlayback = "tunneled-playback"; /** + * If true, the timestamp of each output buffer is derived from the timestamp of the input + * buffer that produced the output. If false, the timestamp of each output buffer is + * derived from the timestamp of the first input buffer. + */ + public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp"; + + /** + * <b>decoder only</b>If true, the codec supports partial (including multiple) access units + * per input buffer. + */ + public static final String FEATURE_FrameParsing = "frame-parsing"; + + /** + * If true, the codec supports multiple access units (for decoding, or to output for + * encoders). If false, the codec only supports single access units. Producing multiple + * access units for output is an optional feature. + */ + public static final String FEATURE_MultipleFrames = "multiple-frames"; + + /** * <b>video decoder only</b>: codec supports queuing partial frames. */ public static final String FEATURE_PartialFrame = "partial-frame"; @@ -497,10 +581,15 @@ public final class MediaCodecInfo { new Feature(FEATURE_SecurePlayback, (1 << 1), false), new Feature(FEATURE_TunneledPlayback, (1 << 2), false), new Feature(FEATURE_PartialFrame, (1 << 3), false), + new Feature(FEATURE_FrameParsing, (1 << 4), false), + new Feature(FEATURE_MultipleFrames, (1 << 5), false), + new Feature(FEATURE_DynamicTimestamp, (1 << 6), false), }; private static final Feature[] encoderFeatures = { new Feature(FEATURE_IntraRefresh, (1 << 0), false), + new Feature(FEATURE_MultipleFrames, (1 << 1), false), + new Feature(FEATURE_DynamicTimestamp, (1 << 2), false), }; /** @hide */ @@ -869,7 +958,7 @@ public final class MediaCodecInfo { CodecCapabilities ret = new CodecCapabilities( new CodecProfileLevel[] { pl }, new int[0], true /* encoder */, - 0 /* flags */, defaultFormat, new MediaFormat() /* info */); + defaultFormat, new MediaFormat() /* info */); if (ret.mError != 0) { return null; } @@ -878,10 +967,10 @@ public final class MediaCodecInfo { /* package private */ CodecCapabilities( CodecProfileLevel[] profLevs, int[] colFmts, - boolean encoder, int flags, + boolean encoder, Map<String, Object>defaultFormatMap, Map<String, Object>capabilitiesMap) { - this(profLevs, colFmts, encoder, flags, + this(profLevs, colFmts, encoder, new MediaFormat(defaultFormatMap), new MediaFormat(capabilitiesMap)); } @@ -889,11 +978,11 @@ public final class MediaCodecInfo { private MediaFormat mCapabilitiesInfo; /* package private */ CodecCapabilities( - CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags, + CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, MediaFormat defaultFormat, MediaFormat info) { final Map<String, Object> map = info.getMap(); colorFormats = colFmts; - mFlagsVerified = flags; + mFlagsVerified = 0; // TODO: remove as it is unused mDefaultFormat = defaultFormat; mCapabilitiesInfo = info; mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME); @@ -1243,6 +1332,7 @@ public final class MediaCodecInfo { private Range<Rational> mBlockAspectRatioRange; private Range<Long> mBlocksPerSecondRange; private Map<Size, Range<Long>> mMeasuredFrameRates; + private Vector<PerformancePoint> mPerformancePoints; private Range<Integer> mFrameRateRange; private int mBlockWidth; @@ -1524,6 +1614,158 @@ public final class MediaCodecInfo { } /** + * Video performance points are a set of standard performance points defined by pixel rate. + */ + public static final class PerformancePoint { + /** + * Frame width in pixels. + */ + public final int width; + + /** + * Frame height in pixels. + */ + public final int height; + + /** + * Frame rate in frames per second. + */ + public final int frameRate; + + /* package private */ + PerformancePoint(int width_, int height_, int frameRate_) { + width = width_; + height = height_; + frameRate = frameRate_; + } + + /** + * Checks whether the performance point covers a media format. + * + * @param format Stream format considered + * + * @return {@code true} if the performance point covers the format. + */ + public boolean covers(@NonNull MediaFormat format) { + // for simplicity, this code assumes a 16x16 block size. + long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16); + long mbps = macroBlocks * frameRate; + + long formatMacroBlocks = + (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16) + * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16); + double formatMbps = + Math.ceil(formatMacroBlocks + * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue()); + return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks + && formatMbps <= mbps; + } + + @Override + public boolean equals(Object o) { + if (o instanceof PerformancePoint) { + PerformancePoint other = (PerformancePoint)o; + return ((long)width * height) == ((long)other.width * other.height) + && frameRate == other.frameRate; + } + return false; + } + + /** 480p 24fps */ + public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24); + /** 576p 25fps */ + public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25); + /** 480p 30fps */ + public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30); + /** 480p 48fps */ + public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48); + /** 576p 50fps */ + public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50); + /** 480p 60fps */ + public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60); + + /** 720p 24fps */ + public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24); + /** 720p 25fps */ + public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25); + /** 720p 30fps */ + public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30); + /** 720p 50fps */ + public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50); + /** 720p 60fps */ + public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60); + /** 720p 100fps */ + public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100); + /** 720p 120fps */ + public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120); + /** 720p 200fps */ + public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200); + /** 720p 240fps */ + public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240); + + /** 1080p 24fps */ + public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24); + /** 1080p 25fps */ + public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25); + /** 1080p 30fps */ + public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30); + /** 1080p 50fps */ + public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50); + /** 1080p 60fps */ + public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60); + /** 1080p 100fps */ + public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100); + /** 1080p 120fps */ + public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120); + /** 1080p 200fps */ + public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200); + /** 1080p 240fps */ + public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240); + + /** 2160p 24fps */ + public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24); + /** 2160p 25fps */ + public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25); + /** 2160p 30fps */ + public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30); + /** 2160p 50fps */ + public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50); + /** 2160p 60fps */ + public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60); + /** 2160p 100fps */ + public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100); + /** 2160p 120fps */ + public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120); + /** 2160p 200fps */ + public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200); + /** 2160p 240fps */ + public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240); + } + + /** + * Returns the supported performance points. May return {@code null} if the codec did not + * publish any performance point information (e.g. the vendor codecs have not been updated + * to the latest android release). May return an empty list if the codec published that + * if does not guarantee any performance points. + * <p> + * This is a performance guarantee provided by the device manufacturer for hardware codecs + * based on hardware capabilities of the device. + * <p> + * The returned list is sorted first by decreasing number of pixels, then by decreasing + * width, and finally by decreasing frame rate. + * Performance points assume a single active codec. For use cases where multiple + * codecs are active, should use that highest pixel count, and add the frame rates of + * each individual codec. + */ + @Nullable + public List<PerformancePoint> getSupportedPerformancePoints() { + if (mPerformancePoints == null) { + return null; + } + return new ArrayList<PerformancePoint>(mPerformancePoints); + } + + /** * Returns whether a given video size ({@code width} and * {@code height}) and {@code frameRate} combination is supported. */ @@ -1659,6 +1901,50 @@ public final class MediaCodecInfo { mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper(); } + private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) { + Vector<PerformancePoint> ret = new Vector<>(); + final String prefix = "performance-point-"; + Set<String> keys = map.keySet(); + for (String key : keys) { + // looking for: performance-point-WIDTHxHEIGHT-range + if (!key.startsWith(prefix)) { + continue; + } + String subKey = key.substring(prefix.length()); + if (subKey.equals("none") && ret.size() == 0) { + // This means that component knowingly did not publish performance points. + // This is different from when the component forgot to publish performance + // points. + return ret; + } + String[] temp = key.split("-"); + if (temp.length != 4) { + continue; + } + String sizeStr = temp[2]; + Size size = Utils.parseSize(sizeStr, null); + if (size == null || size.getWidth() * size.getHeight() <= 0) { + continue; + } + Range<Long> range = Utils.parseLongRange(map.get(key), null); + if (range == null || range.getLower() < 0 || range.getUpper() < 0) { + continue; + } + ret.add(new PerformancePoint( + size.getWidth(), size.getHeight(), range.getLower().intValue())); + } + // check if the component specified no performance point indication + if (ret.size() == 0) { + return null; + } + + // sort reversed by area first, then by frame rate + ret.sort((a, b) -> (a.width * a.height != b.width * b.height ? + (b.width * b.height - a.width * a.height) : + (b.frameRate - a.frameRate))); + return ret; + } + private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) { Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>(); final String prefix = "measured-frame-rate-"; @@ -1770,6 +2056,7 @@ public final class MediaCodecInfo { blockRates = Utils.parseLongRange(map.get("blocks-per-second-range"), null); mMeasuredFrameRates = getMeasuredFrameRates(map); + mPerformancePoints = getPerformancePoints(map); Pair<Range<Integer>, Range<Integer>> sizeRanges = parseWidthHeightRanges(map.get("size-range")); if (sizeRanges != null) { @@ -2879,7 +3166,9 @@ public final class MediaCodecInfo { * {@link MediaCodecInfo.CodecCapabilities#profileLevels} field. */ public static final class CodecProfileLevel { - // from OMX_VIDEO_AVCPROFILETYPE + // These constants were originally in-line with OMX values, but this + // correspondence is no longer maintained. + public static final int AVCProfileBaseline = 0x01; public static final int AVCProfileMain = 0x02; public static final int AVCProfileExtended = 0x04; @@ -2890,7 +3179,6 @@ public final class MediaCodecInfo { public static final int AVCProfileConstrainedBaseline = 0x10000; public static final int AVCProfileConstrainedHigh = 0x80000; - // from OMX_VIDEO_AVCLEVELTYPE public static final int AVCLevel1 = 0x01; public static final int AVCLevel1b = 0x02; public static final int AVCLevel11 = 0x04; @@ -2908,8 +3196,10 @@ public final class MediaCodecInfo { public static final int AVCLevel5 = 0x4000; public static final int AVCLevel51 = 0x8000; public static final int AVCLevel52 = 0x10000; + public static final int AVCLevel6 = 0x20000; + public static final int AVCLevel61 = 0x40000; + public static final int AVCLevel62 = 0x80000; - // from OMX_VIDEO_H263PROFILETYPE public static final int H263ProfileBaseline = 0x01; public static final int H263ProfileH320Coding = 0x02; public static final int H263ProfileBackwardCompatible = 0x04; @@ -2920,7 +3210,6 @@ public final class MediaCodecInfo { public static final int H263ProfileInterlace = 0x80; public static final int H263ProfileHighLatency = 0x100; - // from OMX_VIDEO_H263LEVELTYPE public static final int H263Level10 = 0x01; public static final int H263Level20 = 0x02; public static final int H263Level30 = 0x04; @@ -2930,7 +3219,6 @@ public final class MediaCodecInfo { public static final int H263Level60 = 0x40; public static final int H263Level70 = 0x80; - // from OMX_VIDEO_MPEG4PROFILETYPE public static final int MPEG4ProfileSimple = 0x01; public static final int MPEG4ProfileSimpleScalable = 0x02; public static final int MPEG4ProfileCore = 0x04; @@ -2948,7 +3236,6 @@ public final class MediaCodecInfo { public static final int MPEG4ProfileAdvancedScalable = 0x4000; public static final int MPEG4ProfileAdvancedSimple = 0x8000; - // from OMX_VIDEO_MPEG4LEVELTYPE public static final int MPEG4Level0 = 0x01; public static final int MPEG4Level0b = 0x02; public static final int MPEG4Level1 = 0x04; @@ -2960,7 +3247,6 @@ public final class MediaCodecInfo { public static final int MPEG4Level5 = 0x80; public static final int MPEG4Level6 = 0x100; - // from OMX_VIDEO_MPEG2PROFILETYPE public static final int MPEG2ProfileSimple = 0x00; public static final int MPEG2ProfileMain = 0x01; public static final int MPEG2Profile422 = 0x02; @@ -2968,14 +3254,12 @@ public final class MediaCodecInfo { public static final int MPEG2ProfileSpatial = 0x04; public static final int MPEG2ProfileHigh = 0x05; - // from OMX_VIDEO_MPEG2LEVELTYPE public static final int MPEG2LevelLL = 0x00; public static final int MPEG2LevelML = 0x01; public static final int MPEG2LevelH14 = 0x02; public static final int MPEG2LevelHL = 0x03; public static final int MPEG2LevelHP = 0x04; - // from OMX_AUDIO_AACPROFILETYPE public static final int AACObjectMain = 1; public static final int AACObjectLC = 2; public static final int AACObjectSSR = 3; @@ -2990,16 +3274,13 @@ public final class MediaCodecInfo { /** xHE-AAC (includes USAC) */ public static final int AACObjectXHE = 42; - // from OMX_VIDEO_VP8LEVELTYPE public static final int VP8Level_Version0 = 0x01; public static final int VP8Level_Version1 = 0x02; public static final int VP8Level_Version2 = 0x04; public static final int VP8Level_Version3 = 0x08; - // from OMX_VIDEO_VP8PROFILETYPE public static final int VP8ProfileMain = 0x01; - // from OMX_VIDEO_VP9PROFILETYPE public static final int VP9Profile0 = 0x01; public static final int VP9Profile1 = 0x02; public static final int VP9Profile2 = 0x04; @@ -3010,7 +3291,6 @@ public final class MediaCodecInfo { public static final int VP9Profile2HDR10Plus = 0x4000; public static final int VP9Profile3HDR10Plus = 0x8000; - // from OMX_VIDEO_VP9LEVELTYPE public static final int VP9Level1 = 0x1; public static final int VP9Level11 = 0x2; public static final int VP9Level2 = 0x4; @@ -3026,14 +3306,12 @@ public final class MediaCodecInfo { public static final int VP9Level61 = 0x1000; public static final int VP9Level62 = 0x2000; - // from OMX_VIDEO_HEVCPROFILETYPE public static final int HEVCProfileMain = 0x01; public static final int HEVCProfileMain10 = 0x02; public static final int HEVCProfileMainStill = 0x04; public static final int HEVCProfileMain10HDR10 = 0x1000; public static final int HEVCProfileMain10HDR10Plus = 0x2000; - // from OMX_VIDEO_HEVCLEVELTYPE public static final int HEVCMainTierLevel1 = 0x1; public static final int HEVCHighTierLevel1 = 0x2; public static final int HEVCMainTierLevel2 = 0x4; @@ -3067,7 +3345,6 @@ public final class MediaCodecInfo { HEVCHighTierLevel51 | HEVCHighTierLevel52 | HEVCHighTierLevel6 | HEVCHighTierLevel61 | HEVCHighTierLevel62; - // from OMX_VIDEO_DOLBYVISIONPROFILETYPE public static final int DolbyVisionProfileDvavPer = 0x1; public static final int DolbyVisionProfileDvavPen = 0x2; public static final int DolbyVisionProfileDvheDer = 0x4; @@ -3079,7 +3356,6 @@ public final class MediaCodecInfo { public static final int DolbyVisionProfileDvheSt = 0x100; public static final int DolbyVisionProfileDvavSe = 0x200; - // from OMX_VIDEO_DOLBYVISIONLEVELTYPE public static final int DolbyVisionLevelHd24 = 0x1; public static final int DolbyVisionLevelHd30 = 0x2; public static final int DolbyVisionLevelFhd24 = 0x4; @@ -3090,17 +3366,44 @@ public final class MediaCodecInfo { public static final int DolbyVisionLevelUhd48 = 0x80; public static final int DolbyVisionLevelUhd60 = 0x100; + public static final int AV1Profile0 = 0x1; + public static final int AV1Profile1 = 0x2; + public static final int AV1Profile2 = 0x4; + + public static final int AV1Level2 = 0x1; + public static final int AV1Level21 = 0x2; + public static final int AV1Level22 = 0x4; + public static final int AV1Level23 = 0x8; + public static final int AV1Level3 = 0x10; + public static final int AV1Level31 = 0x20; + public static final int AV1Level32 = 0x40; + public static final int AV1Level33 = 0x80; + public static final int AV1Level4 = 0x100; + public static final int AV1Level41 = 0x200; + public static final int AV1Level42 = 0x400; + public static final int AV1Level43 = 0x800; + public static final int AV1Level5 = 0x1000; + public static final int AV1Level51 = 0x2000; + public static final int AV1Level52 = 0x4000; + public static final int AV1Level53 = 0x8000; + public static final int AV1Level6 = 0x10000; + public static final int AV1Level61 = 0x20000; + public static final int AV1Level62 = 0x40000; + public static final int AV1Level63 = 0x80000; + public static final int AV1Level7 = 0x100000; + public static final int AV1Level71 = 0x200000; + public static final int AV1Level72 = 0x400000; + public static final int AV1Level73 = 0x800000; + /** - * Defined in the OpenMAX IL specs, depending on the type of media - * this can be OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, - * OMX_VIDEO_MPEG4PROFILETYPE, OMX_VIDEO_VP8PROFILETYPE or OMX_VIDEO_VP9PROFILETYPE. + * The profile of the media content. Depending on the type of media this can be + * one of the profile values defined in this class. */ public int profile; /** - * Defined in the OpenMAX IL specs, depending on the type of media - * this can be OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE - * OMX_VIDEO_MPEG4LEVELTYPE, OMX_VIDEO_VP8LEVELTYPE or OMX_VIDEO_VP9LEVELTYPE. + * The level of the media content. Depending on the type of media this can be + * one of the level values defined in this class. * * Note that VP9 decoder on platforms before {@link android.os.Build.VERSION_CODES#N} may * not advertise a profile level support. For those VP9 decoders, please use @@ -3157,7 +3460,7 @@ public final class MediaCodecInfo { } return new MediaCodecInfo( - mName, mIsEncoder, + mName, mCanonicalName, mFlags, caps.toArray(new CodecCapabilities[caps.size()])); } } diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java index 2e4786579d97..a46095484fe7 100644 --- a/media/java/android/media/MediaCodecList.java +++ b/media/java/android/media/MediaCodecList.java @@ -111,12 +111,14 @@ final public class MediaCodecList { caps[typeIx++] = getCodecCapabilities(index, type); } return new MediaCodecInfo( - getCodecName(index), isEncoder(index), caps); + getCodecName(index), getCanonicalName(index), getAttributes(index), caps); } /* package private */ static native final String getCodecName(int index); - /* package private */ static native final boolean isEncoder(int index); + /* package private */ static native final String getCanonicalName(int index); + + /* package private */ static native final int getAttributes(int index); /* package private */ static native final String[] getSupportedTypes(int index); diff --git a/media/java/android/media/MediaConstants.java b/media/java/android/media/MediaConstants.java index 5a5747ae4bab..65b6f55a068a 100644 --- a/media/java/android/media/MediaConstants.java +++ b/media/java/android/media/MediaConstants.java @@ -26,6 +26,7 @@ class MediaConstants { // Bundle key for Parcelable static final String KEY_SESSION2LINK = "android.media.key.SESSION2LINK"; static final String KEY_ALLOWED_COMMANDS = "android.media.key.ALLOWED_COMMANDS"; + static final String KEY_PLAYBACK_ACTIVE = "android.media.key.PLAYBACK_ACTIVE"; private MediaConstants() { } diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java index 165ea412333e..7c5335b71627 100644 --- a/media/java/android/media/MediaController2.java +++ b/media/java/android/media/MediaController2.java @@ -19,6 +19,7 @@ package android.media; import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; import static android.media.MediaConstants.KEY_PACKAGE_NAME; import static android.media.MediaConstants.KEY_PID; +import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE; import static android.media.MediaConstants.KEY_SESSION2LINK; import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR; import static android.media.Session2Command.RESULT_INFO_SKIPPED; @@ -30,7 +31,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -82,6 +82,8 @@ public class MediaController2 implements AutoCloseable { private ArrayMap<ResultReceiver, Integer> mPendingCommands; //@GuardedBy("mLock") private ArraySet<Integer> mRequestedCommandSeqNumbers; + //@GuardedBy("mLock") + private boolean mPlaybackActive; /** * Create a {@link MediaController2} from the {@link Session2Token}. @@ -160,6 +162,18 @@ public class MediaController2 implements AutoCloseable { } /** + * Returns whether the session's playback is active. + * + * @return {@code true} if playback active. {@code false} otherwise. + * @see ControllerCallback#onPlaybackActiveChanged(MediaController2, boolean) + */ + public boolean isPlaybackActive() { + synchronized (mLock) { + return mPlaybackActive; + } + } + + /** * Sends a session command to the session * <p> * @param command the session command @@ -221,89 +235,82 @@ public class MediaController2 implements AutoCloseable { // Called by Controller2Link.onConnected void onConnected(int seq, Bundle connectionResult) { - final long token = Binder.clearCallingIdentity(); - try { - Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK); - Session2CommandGroup allowedCommands = - connectionResult.getParcelable(KEY_ALLOWED_COMMANDS); - if (DEBUG) { - Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder - + ", allowedCommands=" + allowedCommands); - } - if (sessionBinder == null || allowedCommands == null) { - // Connection rejected. - close(); - return; - } - synchronized (mLock) { - mSessionBinder = sessionBinder; - mAllowedCommands = allowedCommands; - // Implementation for the local binder is no-op, - // so can be used without worrying about deadlock. - sessionBinder.linkToDeath(mDeathRecipient, 0); - mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION, - mSessionToken.getPackageName(), sessionBinder); - } - mCallbackExecutor.execute(() -> { - mCallback.onConnected(MediaController2.this, allowedCommands); - }); - } finally { - Binder.restoreCallingIdentity(token); + Session2Link sessionBinder = connectionResult.getParcelable(KEY_SESSION2LINK); + Session2CommandGroup allowedCommands = + connectionResult.getParcelable(KEY_ALLOWED_COMMANDS); + boolean playbackActive = connectionResult.getBoolean(KEY_PLAYBACK_ACTIVE); + if (DEBUG) { + Log.d(TAG, "notifyConnected sessionBinder=" + sessionBinder + + ", allowedCommands=" + allowedCommands); + } + if (sessionBinder == null || allowedCommands == null) { + // Connection rejected. + close(); + return; + } + synchronized (mLock) { + mSessionBinder = sessionBinder; + mAllowedCommands = allowedCommands; + mPlaybackActive = playbackActive; + + // Implementation for the local binder is no-op, + // so can be used without worrying about deadlock. + sessionBinder.linkToDeath(mDeathRecipient, 0); + mConnectedToken = new Session2Token(mSessionToken.getUid(), TYPE_SESSION, + mSessionToken.getPackageName(), sessionBinder); } + mCallbackExecutor.execute(() -> { + mCallback.onConnected(MediaController2.this, allowedCommands); + }); } // Called by Controller2Link.onDisconnected void onDisconnected(int seq) { - final long token = Binder.clearCallingIdentity(); - try { - // close() will call mCallback.onDisconnected - close(); - } finally { - Binder.restoreCallingIdentity(token); + // close() will call mCallback.onDisconnected + close(); + } + + // Called by Controller2Link.onPlaybackActiveChanged + void onPlaybackActiveChanged(int seq, boolean playbackActive) { + synchronized (mLock) { + mPlaybackActive = playbackActive; } + mCallbackExecutor.execute(() -> { + mCallback.onPlaybackActiveChanged(MediaController2.this, playbackActive); + }); } // Called by Controller2Link.onSessionCommand void onSessionCommand(int seq, Session2Command command, Bundle args, @Nullable ResultReceiver resultReceiver) { - final long token = Binder.clearCallingIdentity(); - try { + synchronized (mLock) { + mRequestedCommandSeqNumbers.add(seq); + } + mCallbackExecutor.execute(() -> { + boolean isCanceled; synchronized (mLock) { - mRequestedCommandSeqNumbers.add(seq); + isCanceled = !mRequestedCommandSeqNumbers.remove(seq); } - mCallbackExecutor.execute(() -> { - boolean isCanceled; - synchronized (mLock) { - isCanceled = !mRequestedCommandSeqNumbers.remove(seq); - } - if (isCanceled) { - resultReceiver.send(RESULT_INFO_SKIPPED, null); - return; - } - Session2Command.Result result = mCallback.onSessionCommand( - MediaController2.this, command, args); - if (resultReceiver != null) { - if (result == null) { - throw new RuntimeException("onSessionCommand shouldn't return null"); - } else { - resultReceiver.send(result.getResultCode(), result.getResultData()); - } + if (isCanceled) { + resultReceiver.send(RESULT_INFO_SKIPPED, null); + return; + } + Session2Command.Result result = mCallback.onSessionCommand( + MediaController2.this, command, args); + if (resultReceiver != null) { + if (result == null) { + throw new RuntimeException("onSessionCommand shouldn't return null"); + } else { + resultReceiver.send(result.getResultCode(), result.getResultData()); } - }); - } finally { - Binder.restoreCallingIdentity(token); - } + } + }); } // Called by Controller2Link.onSessionCommand void onCancelCommand(int seq) { - final long token = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { - mRequestedCommandSeqNumbers.remove(seq); - } - } finally { - Binder.restoreCallingIdentity(token); + synchronized (mLock) { + mRequestedCommandSeqNumbers.remove(seq); } } @@ -393,6 +400,17 @@ public class MediaController2 implements AutoCloseable { public void onDisconnected(@NonNull MediaController2 controller) {} /** + * Called when the playback of the session's playback activeness is changed. + * + * @param controller the controller for this event + * @param playbackActive {@code true} if the session's playback is active. + * {@code false} otherwise. + * @see MediaController2#isPlaybackActive() + */ + public void onPlaybackActiveChanged(@NonNull MediaController2 controller, + boolean playbackActive) {} + + /** * Called when the connected session sent a session command. * * @param controller the controller for this event diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index 594a22457cc3..c82b5f6f12a1 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -124,6 +124,7 @@ import java.util.stream.Collectors; public final class MediaFormat { public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"; public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"; + public static final String MIMETYPE_VIDEO_AV1 = "video/av01"; public static final String MIMETYPE_VIDEO_AVC = "video/avc"; public static final String MIMETYPE_VIDEO_HEVC = "video/hevc"; public static final String MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es"; diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java index dceef34596b7..3adac7295fff 100644 --- a/media/java/android/media/MediaSession2.java +++ b/media/java/android/media/MediaSession2.java @@ -19,6 +19,7 @@ package android.media; import static android.media.MediaConstants.KEY_ALLOWED_COMMANDS; import static android.media.MediaConstants.KEY_PACKAGE_NAME; import static android.media.MediaConstants.KEY_PID; +import static android.media.MediaConstants.KEY_PLAYBACK_ACTIVE; import static android.media.MediaConstants.KEY_SESSION2LINK; import static android.media.Session2Command.RESULT_ERROR_UNKNOWN_ERROR; import static android.media.Session2Command.RESULT_INFO_SKIPPED; @@ -87,6 +88,8 @@ public class MediaSession2 implements AutoCloseable { //@GuardedBy("mLock") private boolean mClosed; + //@GuardedBy("mLock") + private boolean mPlaybackActive; MediaSession2(@NonNull Context context, @NonNull String id, PendingIntent sessionActivity, @NonNull Executor callbackExecutor, @NonNull SessionCallback callback) { @@ -215,6 +218,35 @@ public class MediaSession2 implements AutoCloseable { controller.cancelSessionCommand(token); } + /** + * Sets whether the playback is active (i.e. playing something) + * + * @param playbackActive {@code true} if the playback active, {@code false} otherwise. + **/ + public void setPlaybackActive(boolean playbackActive) { + synchronized (mLock) { + if (mPlaybackActive == playbackActive) { + return; + } + mPlaybackActive = playbackActive; + } + List<ControllerInfo> controllerInfos = getConnectedControllers(); + for (ControllerInfo controller : controllerInfos) { + controller.notifyPlaybackActiveChanged(playbackActive); + } + } + + /** + * Returns whehther the playback is active (i.e. playing something) + * + * @return {@code true} if the playback active, {@code false} otherwise. + */ + public boolean isPlaybackActive() { + synchronized (mLock) { + return mPlaybackActive; + } + } + boolean isClosed() { synchronized (mLock) { return mClosed; @@ -239,7 +271,7 @@ public class MediaSession2 implements AutoCloseable { final ControllerInfo controllerInfo = new ControllerInfo(remoteUserInfo, mSessionManager.isTrustedForMediaControl(remoteUserInfo), controller); mCallbackExecutor.execute(() -> { - boolean accept = false; + boolean connected = false; try { if (isClosed()) { return; @@ -249,8 +281,7 @@ public class MediaSession2 implements AutoCloseable { // Don't reject connection for the request from trusted app. // Otherwise server will fail to retrieve session's information to dispatch // media keys to. - accept = controllerInfo.mAllowedCommands != null || controllerInfo.isTrusted(); - if (!accept) { + if (controllerInfo.mAllowedCommands == null && !controllerInfo.isTrusted()) { return; } if (controllerInfo.mAllowedCommands == null) { @@ -276,6 +307,7 @@ public class MediaSession2 implements AutoCloseable { connectionResult.putParcelable(KEY_SESSION2LINK, mSessionStub); connectionResult.putParcelable(KEY_ALLOWED_COMMANDS, controllerInfo.mAllowedCommands); + connectionResult.putBoolean(KEY_PLAYBACK_ACTIVE, isPlaybackActive()); // Double check if session is still there, because close() can be called in // another thread. @@ -283,13 +315,18 @@ public class MediaSession2 implements AutoCloseable { return; } controllerInfo.notifyConnected(connectionResult); + connected = true; } finally { - if (!accept) { + if (!connected) { if (DEBUG) { - Log.d(TAG, "Rejecting connection, controllerInfo=" + controllerInfo); + Log.d(TAG, "Rejecting connection or notifying that session is closed" + + ", controllerInfo=" + controllerInfo); + } + synchronized (mLock) { + mConnectedControllers.remove(controller); } + controllerInfo.notifyDisconnected(); } - controllerInfo.notifyDisconnected(); } }); } @@ -587,6 +624,16 @@ public class MediaSession2 implements AutoCloseable { } } + void notifyPlaybackActiveChanged(boolean playbackActive) { + if (mControllerBinder == null) return; + + try { + mControllerBinder.notifyPlaybackActiveChanged(getNextSeqNumber(), playbackActive); + } catch (RuntimeException e) { + // Controller may be died prematurely. + } + } + void sendSessionCommand(Session2Command command, Bundle args, ResultReceiver resultReceiver) { if (mControllerBinder == null) return; diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java new file mode 100644 index 000000000000..99201c0279bf --- /dev/null +++ b/media/java/android/media/MicrophoneDirection.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +/** + * @hide + */ +public interface MicrophoneDirection { + /** + * @hide + */ + int MIC_DIRECTION_UNSPECIFIED = 0; + + /** + * @hide + */ + int MIC_DIRECTION_FRONT = 1; + + /** + * @hide + */ + int MIC_DIRECTION_BACK = 2; + + /** + * @hide + */ + int MIC_DIRECTION_EXTERNAL = 3; + + /** + * Specifies the logical microphone (for processing). + * + * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*) + * @return retval OK if the call is successful, an error code otherwise. + * @hide + */ + int setMicrophoneDirection(int direction); + + /** + * Specifies the zoom factor (i.e. the field dimension) for the selected microphone + * (for processing). The selected microphone is determined by the use-case for the stream. + * + * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle), + * though 0 (no zoom) to 1 (maximum zoom). + * @return retval OK if the call is successful, an error code otherwise. + * @hide + */ + int setMicrophoneFieldDimension(float zoom); +} diff --git a/media/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java new file mode 100644 index 000000000000..9a346ff4a12e --- /dev/null +++ b/media/java/android/media/session/MediaSessionProviderService.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.session; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +/** + * Abstract class for mainline module services. + * + * @hide // TODO: Make it as a @SystemApi + */ +public abstract class MediaSessionProviderService extends Service { + + @Override + public IBinder onBind(Intent intent) { + // TODO: Return IMediaSessionProviderService.Stub() + return null; + } +} diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 7b07bea3cf1a..406f9dd94bb4 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -648,7 +648,6 @@ static jobject getCodecCapabilitiesObject( capabilities->getSupportedColorFormats(&colorFormats); capabilities->getSupportedProfileLevels(&profileLevels); - uint32_t flags = capabilities->getFlags(); sp<AMessage> details = capabilities->getDetails(); jobject defaultFormatObj = NULL; @@ -687,7 +686,7 @@ static jobject getCodecCapabilitiesObject( return env->NewObject( gCodecInfo.capsClazz, gCodecInfo.capsCtorId, - profileLevelArray.get(), colorFormatsArray.get(), isEncoder, flags, + profileLevelArray.get(), colorFormatsArray.get(), isEncoder, defaultFormatRef.get(), detailsRef.get()); } @@ -700,23 +699,28 @@ status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const return err; } + // TODO: get alias ScopedLocalRef<jstring> nameObject(env, env->NewStringUTF(codecInfo->getCodecName())); + ScopedLocalRef<jstring> canonicalNameObject(env, + env->NewStringUTF(codecInfo->getCodecName())); + + MediaCodecInfo::Attributes attributes = codecInfo->getAttributes(); bool isEncoder = codecInfo->isEncoder(); - Vector<AString> mimes; - codecInfo->getSupportedMimes(&mimes); + Vector<AString> mediaTypes; + codecInfo->getSupportedMediaTypes(&mediaTypes); ScopedLocalRef<jobjectArray> capsArrayObj(env, - env->NewObjectArray(mimes.size(), gCodecInfo.capsClazz, NULL)); + env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL)); - for (size_t i = 0; i < mimes.size(); i++) { + for (size_t i = 0; i < mediaTypes.size(); i++) { const sp<MediaCodecInfo::Capabilities> caps = - codecInfo->getCapabilitiesFor(mimes[i].c_str()); + codecInfo->getCapabilitiesFor(mediaTypes[i].c_str()); ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject( - env, mimes[i].c_str(), isEncoder, caps)); + env, mediaTypes[i].c_str(), isEncoder, caps)); env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get()); } @@ -726,10 +730,10 @@ status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const CHECK(codecInfoClazz.get() != NULL); jmethodID codecInfoCtorID = env->GetMethodID(codecInfoClazz.get(), "<init>", - "(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V"); + "(Ljava/lang/String;Ljava/lang/String;I[Landroid/media/MediaCodecInfo$CodecCapabilities;)V"); *codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID, - nameObject.get(), isEncoder, capsArrayObj.get()); + nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get()); return OK; } @@ -2079,7 +2083,7 @@ static void android_media_MediaCodec_native_init(JNIEnv *env) { gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get()); method = env->GetMethodID(clazz.get(), "<init>", - "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI" + "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ" "Ljava/util/Map;Ljava/util/Map;)V"); CHECK(method != NULL); gCodecInfo.capsCtorId = method; @@ -2217,7 +2221,7 @@ static const JNINativeMethod gMethods[] = { { "getImage", "(ZI)Landroid/media/Image;", (void *)android_media_MediaCodec_getImage }, - { "getName", "()Ljava/lang/String;", + { "getCanonicalName", "()Ljava/lang/String;", (void *)android_media_MediaCodec_getName }, { "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;", diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp index 8de11caf7d7a..cf1494296756 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -41,6 +41,21 @@ static sp<IMediaCodecList> getCodecList(JNIEnv *env) { return mcl; } +static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) { + sp<IMediaCodecList> mcl = getCodecList(env); + if (mcl == NULL) { + // Runtime exception already pending. + return NULL; + } + + sp<MediaCodecInfo> info = mcl->getCodecInfo(index); + if (info == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + } + + return info; +} + static jint android_media_MediaCodecList_getCodecCount( JNIEnv *env, jobject /* thiz */) { sp<IMediaCodecList> mcl = getCodecList(env); @@ -53,15 +68,22 @@ static jint android_media_MediaCodecList_getCodecCount( static jstring android_media_MediaCodecList_getCodecName( JNIEnv *env, jobject /* thiz */, jint index) { - sp<IMediaCodecList> mcl = getCodecList(env); - if (mcl == NULL) { + sp<MediaCodecInfo> info = getCodecInfo(env, index); + if (info == NULL) { // Runtime exception already pending. return NULL; } - const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index); + // TODO: support aliases + const char *name = info->getCodecName(); + return env->NewStringUTF(name); +} + +static jstring android_media_MediaCodecList_getCanonicalName( + JNIEnv *env, jobject /* thiz */, jint index) { + sp<MediaCodecInfo> info = getCodecInfo(env, index); if (info == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + // Runtime exception already pending. return NULL; } @@ -94,39 +116,27 @@ static jint android_media_MediaCodecList_findCodecByName( return ret; } -static jboolean android_media_MediaCodecList_isEncoder( +static jboolean android_media_MediaCodecList_getAttributes( JNIEnv *env, jobject /* thiz */, jint index) { - sp<IMediaCodecList> mcl = getCodecList(env); - if (mcl == NULL) { - // Runtime exception already pending. - return false; - } - - const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index); + sp<MediaCodecInfo> info = getCodecInfo(env, index); if (info == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return false; + // Runtime exception already pending. + return 0; } - return info->isEncoder(); + return info->getAttributes(); } static jarray android_media_MediaCodecList_getSupportedTypes( JNIEnv *env, jobject /* thiz */, jint index) { - sp<IMediaCodecList> mcl = getCodecList(env); - if (mcl == NULL) { - // Runtime exception already pending. - return NULL; - } - - const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index); + sp<MediaCodecInfo> info = getCodecInfo(env, index); if (info == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + // Runtime exception already pending. return NULL; } Vector<AString> types; - info->getSupportedMimes(&types); + info->getSupportedMediaTypes(&types); jclass clazz = env->FindClass("java/lang/String"); CHECK(clazz != NULL); @@ -150,17 +160,12 @@ static jobject android_media_MediaCodecList_getCodecCapabilities( return NULL; } - sp<IMediaCodecList> mcl = getCodecList(env); - if (mcl == NULL) { + sp<MediaCodecInfo> info = getCodecInfo(env, index); + if (info == NULL) { // Runtime exception already pending. return NULL; } - const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index); - if (info == NULL) { - jniThrowException(env, "java/lang/IllegalArgumentException", NULL); - return NULL; - } const char *typeStr = env->GetStringUTFChars(type, NULL); if (typeStr == NULL) { @@ -186,7 +191,6 @@ static jobject android_media_MediaCodecList_getCodecCapabilities( capabilities->getSupportedColorFormats(&colorFormats); capabilities->getSupportedProfileLevels(&profileLevels); - uint32_t flags = capabilities->getFlags(); sp<AMessage> details = capabilities->getDetails(); bool isEncoder = info->isEncoder(); @@ -240,11 +244,11 @@ static jobject android_media_MediaCodecList_getCodecCapabilities( } jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>", - "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI" + "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ" "Ljava/util/Map;Ljava/util/Map;)V"); jobject caps = env->NewObject(capsClazz, capsConstructID, - profileLevelArray, colorFormatsArray, isEncoder, flags, + profileLevelArray, colorFormatsArray, isEncoder, defaultFormatObj, infoObj); env->DeleteLocalRef(profileLevelArray); @@ -288,9 +292,15 @@ static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) { static const JNINativeMethod gMethods[] = { { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount }, + + { "getCanonicalName", "(I)Ljava/lang/String;", + (void *)android_media_MediaCodecList_getCanonicalName }, + { "getCodecName", "(I)Ljava/lang/String;", (void *)android_media_MediaCodecList_getCodecName }, - { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder }, + + { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes }, + { "getSupportedTypes", "(I)[Ljava/lang/String;", (void *)android_media_MediaCodecList_getSupportedTypes }, diff --git a/media/packages/MediaCore/Android.bp b/media/packages/MediaCore/Android.bp new file mode 100644 index 000000000000..c7fd58bf933a --- /dev/null +++ b/media/packages/MediaCore/Android.bp @@ -0,0 +1,21 @@ +android_app { + name: "MediaCore", + + srcs: [ + "src/**/*.java", + ], + + static_libs: [ + // TODO: Temporarily statically linked. Should go into "libs" + "media1", + ], + + // System app + platform_apis: true, + + // Privileged app + privileged: true, + + // Make sure that the implementation only relies on SDK or system APIs. + sdk_version: "system_current", +} diff --git a/media/packages/MediaCore/AndroidManifest.xml b/media/packages/MediaCore/AndroidManifest.xml new file mode 100644 index 000000000000..4e2b274511e8 --- /dev/null +++ b/media/packages/MediaCore/AndroidManifest.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/AndroidManifest.xml +** +** Copyright 2019, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.media" coreApp="true" android:sharedUserId="android.uid.system" + android:sharedUserLabel="@string/android_system_label"> + <application android:process="system" + android:persistent="true" + android:directBootAware="true"> + <service android:name="AmlMediaSessionProviderService" android:singleUser="true"> + <intent-filter> + <action android:name="android.media.session.MediaSessionProviderService"/> + </intent-filter> + </service> + </application> +</manifest> diff --git a/media/packages/MediaCore/res/values/strings.xml b/media/packages/MediaCore/res/values/strings.xml new file mode 100644 index 000000000000..59fd635b905f --- /dev/null +++ b/media/packages/MediaCore/res/values/strings.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources> + <!-- Label for the Android system components when they are shown to the user. --> + <string name="android_system_label" translatable="false">Android System</string> +</resources> + diff --git a/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java new file mode 100644 index 000000000000..43b95ab7ebdb --- /dev/null +++ b/media/packages/MediaCore/src/com/android/media/AmlMediaSessionProviderService.java @@ -0,0 +1,37 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.media; + +import android.content.Context; +import android.media.session.MediaSessionProviderService; +import android.os.PowerManager; +import android.util.Log; + +/** + * System implementation of MediaSessionProviderService + */ +public class AmlMediaSessionProviderService extends MediaSessionProviderService { + private static final String TAG = "AmlMediaSessionProviderS"; + static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private Context mContext; + + public AmlMediaSessionProviderService(Context context) { + mContext = context; + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + } +} diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp index 8e5821024cee..c3b2e2526ea8 100644 --- a/native/android/sensor.cpp +++ b/native/android/sensor.cpp @@ -342,3 +342,8 @@ int ASensor_getHighestDirectReportRateLevel(ASensor const *sensor) { RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP); return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel(); } + +int ASensor_getHandle(ASensor const* sensor) { + RETURN_IF_SENSOR_IS_NULL(ASENSOR_INVALID); + return static_cast<Sensor const*>(sensor)->getHandle(); +} diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml index 0d72657bb2df..6f7f39810608 100644 --- a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml +++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml @@ -19,15 +19,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - <TextClock + <include android:id="@+id/digital_clock" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:letterSpacing="0.03" - android:singleLine="true" - style="@style/widget_big" - android:format12Hour="@string/keyguard_widget_12_hours_format" - android:format24Hour="@string/keyguard_widget_24_hours_format" + layout="@layout/text_clock" /> <com.android.keyguard.clock.ImageClock android:id="@+id/analog_clock" diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml index cf4a573834dd..e88e2c94e74f 100644 --- a/packages/SystemUI/res-keyguard/layout/digital_clock.xml +++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml @@ -20,16 +20,9 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_alignParentTop="true"> - <TextClock + <include android:id="@+id/lock_screen_clock" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:letterSpacing="0.03" - android:singleLine="true" - style="@style/widget_big" - android:format12Hour="@string/keyguard_widget_12_hours_format" - android:format24Hour="@string/keyguard_widget_24_hours_format" /> + layout="@layout/text_clock" /> </FrameLayout> diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml index d52866fbd444..463367b2c600 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml @@ -30,17 +30,9 @@ android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_alignParentTop="true"> - <TextClock + <include android:id="@+id/default_clock_view" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:letterSpacing="0.03" - android:textColor="?attr/wallpaperTextColor" - android:singleLine="true" - style="@style/widget_big" - android:format12Hour="@string/keyguard_widget_12_hours_format" - android:format24Hour="@string/keyguard_widget_24_hours_format" /> + layout="@layout/text_clock" /> </FrameLayout> <include layout="@layout/keyguard_status_area" android:id="@+id/keyguard_status_area" diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml index 9033fce881c4..64b676f55fd6 100644 --- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml +++ b/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml @@ -19,15 +19,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - <TextClock + <include android:id="@+id/digital_clock" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:letterSpacing="0.03" - android:singleLine="true" - style="@style/widget_big" - android:format12Hour="@string/keyguard_widget_12_hours_format" - android:format24Hour="@string/keyguard_widget_24_hours_format" + layout="@layout/text_clock" /> <com.android.keyguard.clock.StretchAnalogClock android:id="@+id/analog_clock" diff --git a/packages/SystemUI/res-keyguard/layout/text_clock.xml b/packages/SystemUI/res-keyguard/layout/text_clock.xml new file mode 100644 index 000000000000..b61ad9c4fc11 --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/text_clock.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<TextClock + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:letterSpacing="0.03" + android:textColor="?attr/wallpaperTextColor" + android:singleLine="true" + style="@style/widget_big" + android:format12Hour="@string/keyguard_widget_12_hours_format" + android:format24Hour="@string/keyguard_widget_24_hours_format" + android:elegantTextHeight="false" +/> diff --git a/packages/SystemUI/res-keyguard/layout/type_clock.xml b/packages/SystemUI/res-keyguard/layout/type_clock.xml new file mode 100644 index 000000000000..21c64e9c7dbe --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/type_clock.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<com.android.keyguard.clock.ClockLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + <com.android.keyguard.clock.TypographicClock + android:id="@+id/type_clock" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" + > + <TextView + android:id="@+id/header" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="50dp" + style="@style/widget_big" + android:textColor="@color/typeClockAccentColor" + android:text="@string/type_clock_header" + android:textSize="40dp" + /> + <TextView + android:id="@+id/hour" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="50dp" + style="@style/widget_big" + android:textSize="40dp" + /> + <TextView + android:id="@+id/minute" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="50dp" + style="@style/widget_big" + android:textSize="40dp" + /> + </com.android.keyguard.clock.TypographicClock> +</com.android.keyguard.clock.ClockLayout> diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml index 7a849ebd481d..74ee7ffad3f6 100644 --- a/packages/SystemUI/res-keyguard/values/colors.xml +++ b/packages/SystemUI/res-keyguard/values/colors.xml @@ -19,4 +19,6 @@ <color name="bubbleHourHandColor">#C97343</color> <!-- Default color for minute hand of Bubble clock. --> <color name="bubbleMinuteHandColor">#F5C983</color> + <!-- Accent color for Typographic clock. --> + <color name="typeClockAccentColor">#F5C983</color> </resources> diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 1d5aa6d76991..7432f9cde639 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -402,4 +402,87 @@ number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item> </plurals> + <!-- Header for typographic clock face. [CHAR LIMIT=8] --> + <string name="type_clock_header">It\u2019s</string> + + <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=8] --> + <string-array name="type_clock_hours"> + <item>Twelve</item> + <item>One</item> + <item>Two</item> + <item>Three</item> + <item>Four</item> + <item>Five</item> + <item>Six</item> + <item>Seven</item> + <item>Eight</item> + <item>Nine</item> + <item>Ten</item> + <item>Eleven</item> + </string-array> + + <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=16] --> + <string-array name="type_clock_minutes"> + <item>O\u2019Clock</item> + <item>O\u2019One</item> + <item>O\u2019Two</item> + <item>O\u2019Three</item> + <item>O\u2019Four</item> + <item>O\u2019Five</item> + <item>O\u2019Six</item> + <item>O\u2019Seven</item> + <item>O\u2019Eight</item> + <item>O\u2019Nine</item> + <item>Ten</item> + <item>Eleven</item> + <item>Twelve</item> + <item>Thirteen</item> + <item>Fourteen</item> + <item>Fifteen</item> + <item>Sixteen</item> + <item>Seventeen</item> + <item>Eighteen</item> + <item>Nineteen</item> + <item>Twenty</item> + <item>Twenty\nOne</item> + <item>Twenty\nTwo</item> + <item>Twenty\nThree</item> + <item>Twenty\nFour</item> + <item>Twenty\nFive</item> + <item>Twenty\nSix</item> + <item>Twenty\nSeven</item> + <item>Twenty\nEight</item> + <item>Twenty\nNine</item> + <item>Thirty</item> + <item>Thirty\nOne</item> + <item>Thirty\nTwo</item> + <item>Thirty\nThree</item> + <item>Thirty\nFour</item> + <item>Thirty\nFive</item> + <item>Thirty\nSix</item> + <item>Thirty\nSeven</item> + <item>Thirty\nEight</item> + <item>Thirty\nNine</item> + <item>Forty</item> + <item>Forty\nOne</item> + <item>Forty\nTwo</item> + <item>Forty\nThree</item> + <item>Forty\nFour</item> + <item>Forty\nFive</item> + <item>Forty\nSix</item> + <item>Forty\nSeven</item> + <item>Forty\nEight</item> + <item>Forty\nNine</item> + <item>Fifty</item> + <item>Fifty\nOne</item> + <item>Fifty\nTwo</item> + <item>Fifty\nThree</item> + <item>Fifty\nFour</item> + <item>Fifty\nFive</item> + <item>Fifty\nSix</item> + <item>Fifty\nSeven</item> + <item>Fifty\nEight</item> + <item>Fifty\nNine</item> + </string-array> + </resources> diff --git a/packages/SystemUI/res/layout/global_actions_wrapped.xml b/packages/SystemUI/res/layout/global_actions_wrapped.xml index 7f4e0d21078f..f932303473bd 100644 --- a/packages/SystemUI/res/layout/global_actions_wrapped.xml +++ b/packages/SystemUI/res/layout/global_actions_wrapped.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <com.android.systemui.HardwareUiLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@id/global_actions_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top|right" diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 476089aa3aac..98f0cbe29110 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -106,7 +106,7 @@ <!-- The default tiles to display in QuickSettings --> <string name="quick_settings_tiles_default" translatable="false"> - wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast + wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,sensorprivacy </string> <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 633f8686b804..bd34beac7fd6 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -114,5 +114,8 @@ <item type="id" name="aod_mask_transition_progress_tag" /> <item type="id" name="aod_mask_transition_progress_end_tag" /> <item type="id" name="aod_mask_transition_progress_start_tag" /> + + <!-- Global Actions Menu --> + <item type="id" name="global_actions_view" /> </resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index a8094d20d5a2..1aff3949a74b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -20,6 +20,7 @@ import androidx.annotation.VisibleForTesting; import com.android.keyguard.clock.BubbleClockController; import com.android.keyguard.clock.StretchAnalogClockController; +import com.android.keyguard.clock.TypeClockController; import com.android.systemui.Dependency; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.statusbar.StatusBarState; @@ -153,6 +154,12 @@ public class KeyguardClockSwitch extends RelativeLayout { Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, StretchAnalogClockController.class.getName(), () -> StretchAnalogClockController.build(mLayoutInflater))) + .withDefault( + new SettingsGattedSupplier( + mContentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, + TypeClockController.class.getName(), + () -> TypeClockController.build(mLayoutInflater))) .build(); mContentResolver.registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), @@ -248,10 +255,6 @@ public class KeyguardClockSwitch extends RelativeLayout { mClockView.setShowCurrentUserTime(showCurrentUserTime); } - public void setElegantTextHeight(boolean elegant) { - mClockView.setElegantTextHeight(elegant); - } - public void setTextSize(int unit, float size) { mClockView.setTextSize(unit, size); } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index f0cdc890306f..7ae4c41d318f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -202,10 +202,6 @@ public class KeyguardStatusView extends GridLayout implements updateOwnerInfo(); updateLogoutView(); updateDark(); - - // Disable elegant text height because our fancy colon makes the ymin value huge for no - // reason. - mClockView.setElegantTextHeight(false); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java index 5aa566848732..3591dc82c8ec 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -36,6 +36,7 @@ public class ClockLayout extends FrameLayout { */ private View mDigitalClock; private View mAnalogClock; + private View mTypeClock; /** * Pixel shifting amplitidues used to prevent screen burn-in. @@ -60,6 +61,7 @@ public class ClockLayout extends FrameLayout { super.onFinishInflate(); mDigitalClock = findViewById(R.id.digital_clock); mAnalogClock = findViewById(R.id.analog_clock); + mTypeClock = findViewById(R.id.type_clock); // Get pixel shifting X, Y amplitudes from resources. Resources resources = getResources(); @@ -89,5 +91,11 @@ public class ClockLayout extends FrameLayout { mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight())) + offsetY); } + + // Put the typographic clock part way down the screen. + if (mTypeClock != null) { + mTypeClock.setX(offsetX); + mTypeClock.setY(0.2f * getHeight() + offsetY); + } } } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java index 91cec86392d6..8734754541a6 100644 --- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java +++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java @@ -80,6 +80,7 @@ public class StretchAnalogClock extends View { */ public void setMinuteHandColor(int color) { mMinutePaint.setColor(color); + invalidate(); } private void init() { diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java new file mode 100644 index 000000000000..17d929dc8a3b --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.keyguard.clock; + +import android.graphics.Paint.Style; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.keyguard.R; +import com.android.systemui.plugins.ClockPlugin; + +import java.util.TimeZone; + +/** + * Plugin for a custom Typographic clock face that displays the time in words. + */ +public class TypeClockController implements ClockPlugin { + + /** + * Custom clock shown on AOD screen and behind stack scroller on lock. + */ + private View mView; + private TypographicClock mTypeClock; + + /** + * Small clock shown on lock screen above stack scroller. + */ + private View mLockClockContainer; + + /** + * Controller for transition into dark state. + */ + private CrossFadeDarkController mDarkController; + + private TypeClockController() {} + + /** + * Create a TypeClockController instance. + * + * @param inflater Inflater used to inflate custom clock views. + */ + public static TypeClockController build(LayoutInflater inflater) { + TypeClockController controller = new TypeClockController(); + controller.createViews(inflater); + return controller; + } + + private void createViews(LayoutInflater inflater) { + mView = inflater.inflate(R.layout.type_clock, null); + mTypeClock = mView.findViewById(R.id.type_clock); + + // For now, this view is used to hide the default digital clock. + // Need better transition to lock screen. + mLockClockContainer = inflater.inflate(R.layout.digital_clock, null); + mLockClockContainer.setVisibility(View.GONE); + } + + @Override + public View getView() { + return mLockClockContainer; + } + + @Override + public View getBigClockView() { + return mView; + } + + @Override + public void setStyle(Style style) {} + + @Override + public void setTextColor(int color) { + mTypeClock.setTextColor(color); + } + + @Override + public void dozeTimeTick() { + mTypeClock.onTimeChanged(); + } + + @Override + public void setDarkAmount(float darkAmount) {} + + @Override + public void onTimeZoneChanged(TimeZone timeZone) { + mTypeClock.onTimeZoneChanged(timeZone); + } + + @Override + public boolean shouldShowStatusArea() { + return false; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java new file mode 100644 index 000000000000..5f9da3ee33bb --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.keyguard.clock; + +import android.content.Context; +import android.content.res.Resources; +import android.text.format.DateFormat; +import android.util.AttributeSet; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.keyguard.R; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; + +/** + * Clock that presents the time in words. + */ +public class TypographicClock extends LinearLayout { + + private final String[] mHours; + private final String[] mMinutes; + private TextView mHeaderText; + private TextView mHourText; + private TextView mMinuteText; + private Calendar mTime; + private String mDescFormat; + private TimeZone mTimeZone; + + public TypographicClock(Context context) { + this(context, null); + } + + public TypographicClock(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TypographicClock(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mTime = Calendar.getInstance(); + mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern(); + Resources res = context.getResources(); + mHours = res.getStringArray(R.array.type_clock_hours); + mMinutes = res.getStringArray(R.array.type_clock_minutes); + } + + /** + * Call when the time changes to update the text of the time. + */ + public void onTimeChanged() { + mTime.setTimeInMillis(System.currentTimeMillis()); + setContentDescription(DateFormat.format(mDescFormat, mTime)); + final int hour = mTime.get(Calendar.HOUR); + mHourText.setText(mHours[hour % 12]); + final int minute = mTime.get(Calendar.MINUTE); + mMinuteText.setText(mMinutes[minute % 60]); + invalidate(); + } + + /** + * Call when the time zone has changed to update clock time. + * + * @param timeZone The updated time zone that will be used. + */ + public void onTimeZoneChanged(TimeZone timeZone) { + mTimeZone = timeZone; + mTime.setTimeZone(timeZone); + } + + /** + * Set the color of the text used to display the time. + * + * This is necessary when the wallpaper shown behind the clock on the + * lock screen changes. + */ + public void setTextColor(int color) { + mHourText.setTextColor(color); + mMinuteText.setTextColor(color); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mHeaderText = findViewById(R.id.header); + mHourText = findViewById(R.id.hour); + mMinuteText = findViewById(R.id.minute); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault()); + onTimeChanged(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java index 16e869e9d317..e28aa9d369cb 100644 --- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java +++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java @@ -37,23 +37,25 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.leak.RotationUtils; -public class HardwareUiLayout extends LinearLayout implements Tunable { +/** + * Layout for placing two containers at a specific physical position on the device, relative to the + * device's hardware, regardless of screen rotation. + */ +public class HardwareUiLayout extends MultiListLayout implements Tunable { private static final String EDGE_BLEED = "sysui_hwui_edge_bleed"; private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider"; private final int[] mTmp2 = new int[2]; - private View mList; - private View mSeparatedView; + private ViewGroup mList; + private ViewGroup mSeparatedView; private int mOldHeight; private boolean mAnimating; private AnimatorSet mAnimation; private View mDivision; - private boolean mHasOutsideTouch; private HardwareBgDrawable mListBackground; private HardwareBgDrawable mSeparatedViewBackground; private Animator mAnimator; private boolean mCollapse; - private boolean mHasSeparatedButton; private int mEndPoint; private boolean mEdgeBleed; private boolean mRoundedDivider; @@ -67,6 +69,35 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } @Override + protected ViewGroup getSeparatedView() { + return findViewById(com.android.systemui.R.id.separated_button); + } + + @Override + protected ViewGroup getListView() { + return findViewById(android.R.id.list); + } + + @Override + public void removeAllItems() { + if (mList != null) { + mList.removeAllViews(); + } + if (mSeparatedView != null) { + mSeparatedView.removeAllViews(); + } + } + + @Override + public ViewGroup getParentView(boolean separated, int index) { + if (separated) { + return getSeparatedView(); + } else { + return getListView(); + } + } + + @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); updateSettings(); @@ -137,9 +168,9 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mList == null) { if (getChildCount() != 0) { - mList = getChildAt(0); + mList = getListView(); mList.setBackground(mListBackground); - mSeparatedView = getChildAt(1); + mSeparatedView = getSeparatedView(); mSeparatedView.setBackground(mSeparatedViewBackground); updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding()); mOldHeight = mList.getMeasuredHeight(); @@ -187,7 +218,7 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { } else { rotateLeft(); } - if (mHasSeparatedButton) { + if (mHasSeparatedView) { if (from == ROTATION_SEASCAPE || to == ROTATION_SEASCAPE) { // Separated view has top margin, so seascape separated view need special rotation, // not a full left or right rotation. @@ -408,8 +439,8 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { if (mList == null) return; // If got separated button, setRotatedBackground to false, // all items won't get white background. - mListBackground.setRotatedBackground(mHasSeparatedButton); - mSeparatedViewBackground.setRotatedBackground(mHasSeparatedButton); + mListBackground.setRotatedBackground(mHasSeparatedView); + mSeparatedViewBackground.setRotatedBackground(mHasSeparatedView); if (mDivision != null && mDivision.getVisibility() == VISIBLE) { int index = mRotatedBackground ? 0 : 1; mDivision.getLocationOnScreen(mTmp2); @@ -460,21 +491,21 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { case RotationUtils.ROTATION_LANDSCAPE: defaultTopPadding = getPaddingLeft(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); - separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0; + separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP; break; case RotationUtils.ROTATION_SEASCAPE: defaultTopPadding = getPaddingRight(); viewsTotalHeight = mList.getMeasuredWidth() + mSeparatedView.getMeasuredWidth(); - separatedViewTopMargin = mHasSeparatedButton ? params.leftMargin : 0; + separatedViewTopMargin = mHasSeparatedView ? params.leftMargin : 0; screenHeight = getMeasuredWidth(); targetGravity = Gravity.CENTER_HORIZONTAL|Gravity.BOTTOM; break; default: // Portrait defaultTopPadding = getPaddingTop(); viewsTotalHeight = mList.getMeasuredHeight() + mSeparatedView.getMeasuredHeight(); - separatedViewTopMargin = mHasSeparatedButton ? params.topMargin : 0; + separatedViewTopMargin = mHasSeparatedView ? params.topMargin : 0; screenHeight = getMeasuredHeight(); targetGravity = Gravity.CENTER_VERTICAL|Gravity.RIGHT; break; @@ -491,30 +522,10 @@ public class HardwareUiLayout extends LinearLayout implements Tunable { return super.getOutlineProvider(); } - public void setOutsideTouchListener(OnClickListener onClickListener) { - mHasOutsideTouch = true; - requestLayout(); - setOnClickListener(onClickListener); - setClickable(true); - setFocusable(true); - } - public void setCollapse() { mCollapse = true; } - public void setHasSeparatedButton(boolean hasSeparatedButton) { - mHasSeparatedButton = hasSeparatedButton; - } - - public static HardwareUiLayout get(View v) { - if (v instanceof HardwareUiLayout) return (HardwareUiLayout) v; - if (v.getParent() instanceof View) { - return get((View) v.getParent()); - } - return null; - } - private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> { if (mHasOutsideTouch || (mList == null)) { inoutInfo.setTouchableInsets( diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java new file mode 100644 index 000000000000..0c7a9a9fffd2 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +/** + * Layout class representing the Global Actions menu which appears when the power button is held. + */ +public abstract class MultiListLayout extends LinearLayout { + boolean mHasOutsideTouch; + boolean mHasSeparatedView; + + int mExpectedSeparatedItemCount; + int mExpectedListItemCount; + + public MultiListLayout(Context context, AttributeSet attrs) { + super(context, attrs); + } + + protected abstract ViewGroup getSeparatedView(); + + protected abstract ViewGroup getListView(); + + /** + * Removes all child items from the separated and list views, if they exist. + */ + public abstract void removeAllItems(); + + /** + * Get the parent view which will be used to contain the item at the specified index. + * @param separated Whether or not this index refers to a position in the separated or list + * container. + * @param index The index of the item within the container. + * @return The parent ViewGroup which will be used to contain the specified item + * after it has been added to the layout. + */ + public abstract ViewGroup getParentView(boolean separated, int index); + + /** + * Sets the divided view, which may have a differently-colored background. + */ + public abstract void setDivisionView(View v); + + /** + * Set the view accessibility delegate for the list view container. + */ + public void setListViewAccessibilityDelegate(View.AccessibilityDelegate delegate) { + getListView().setAccessibilityDelegate(delegate); + } + + protected void setSeparatedViewVisibility(boolean visible) { + getSeparatedView().setVisibility(visible ? View.VISIBLE : View.GONE); + } + + /** + * Sets the number of items expected to be rendered in the separated container. This allows the + * layout to correctly determine which parent containers will be used for items before they have + * beenadded to the layout. + * @param count The number of items expected. + */ + public void setExpectedSeparatedItemCount(int count) { + mExpectedSeparatedItemCount = count; + } + + /** + * Sets the number of items expected to be rendered in the list container. This allows the + * layout to correctly determine which parent containers will be used for items before they have + * beenadded to the layout. + * @param count The number of items expected. + */ + public void setExpectedListItemCount(int count) { + mExpectedListItemCount = count; + } + + /** + * Sets whether the separated view should be shown, and handles updating visibility on + * that view. + */ + public void setHasSeparatedView(boolean hasSeparatedView) { + mHasSeparatedView = hasSeparatedView; + setSeparatedViewVisibility(hasSeparatedView); + } + + /** + * Sets this layout to respond to an outside touch listener. + */ + public void setOutsideTouchListener(OnClickListener onClickListener) { + mHasOutsideTouch = true; + requestLayout(); + setOnClickListener(onClickListener); + setClickable(true); + setFocusable(true); + } + + /** + * Retrieve the MultiListLayout associated with the given view. + */ + public static MultiListLayout get(View v) { + if (v instanceof MultiListLayout) return (MultiListLayout) v; + if (v.getParent() instanceof View) { + return get((View) v.getParent()); + } + return null; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 268245bd4acd..7b18fad0e105 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -67,10 +67,8 @@ import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.BaseAdapter; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ImageView.ScaleType; -import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.R; @@ -86,8 +84,8 @@ import com.android.internal.util.ScreenRecordHelper; import com.android.internal.util.ScreenshotHelper; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; -import com.android.systemui.HardwareUiLayout; import com.android.systemui.Interpolators; +import com.android.systemui.MultiListLayout; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.statusbar.phone.ScrimController; @@ -490,6 +488,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, public boolean showBeforeProvisioning() { return true; } + + @Override + public boolean shouldBeSeparated() { + return true; + } } private final class RestartAction extends SinglePressAction implements LongPressAction { @@ -926,6 +929,34 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return getItem(position).isEnabled(); } + public ArrayList<Action> getSeparatedActions(boolean shouldUseSeparatedView) { + ArrayList<Action> separatedActions = new ArrayList<Action>(); + if (!shouldUseSeparatedView) { + return separatedActions; + } + for (int i = 0; i < mItems.size(); i++) { + final Action action = mItems.get(i); + if (action.shouldBeSeparated()) { + separatedActions.add(action); + } + } + return separatedActions; + } + + public ArrayList<Action> getListActions(boolean shouldUseSeparatedView) { + if (!shouldUseSeparatedView) { + return new ArrayList<Action>(mItems); + } + ArrayList<Action> listActions = new ArrayList<Action>(); + for (int i = 0; i < mItems.size(); i++) { + final Action action = mItems.get(i); + if (!action.shouldBeSeparated()) { + listActions.add(action); + } + } + return listActions; + } + @Override public boolean areAllItemsEnabled() { return false; @@ -965,7 +996,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext)); // Everything but screenshot, the last item, gets white background. if (position == getCount() - 1) { - HardwareUiLayout.get(parent).setDivisionView(view); + MultiListLayout.get(parent).setDivisionView(view); } return view; } @@ -1004,6 +1035,10 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, boolean showBeforeProvisioning(); boolean isEnabled(); + + default boolean shouldBeSeparated() { + return false; + } } /** @@ -1423,9 +1458,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final Context mContext; private final MyAdapter mAdapter; - private final LinearLayout mListView; - private final FrameLayout mSeparatedView; - private final HardwareUiLayout mHardwareLayout; + private final MultiListLayout mGlobalActionsLayout; private final OnClickListener mClickListener; private final OnItemLongClickListener mLongClickListener; private final GradientDrawable mGradientDrawable; @@ -1466,16 +1499,11 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY); setContentView(com.android.systemui.R.layout.global_actions_wrapped); - mListView = findViewById(android.R.id.list); - mSeparatedView = findViewById(com.android.systemui.R.id.separated_button); - if (!mShouldDisplaySeparatedButton) { - mSeparatedView.setVisibility(View.GONE); - } - mHardwareLayout = HardwareUiLayout.get(mListView); - mHardwareLayout.setOutsideTouchListener(view -> dismiss()); - mHardwareLayout.setHasSeparatedButton(mShouldDisplaySeparatedButton); - setTitle(R.string.global_actions); - mListView.setAccessibilityDelegate(new View.AccessibilityDelegate() { + mGlobalActionsLayout = (MultiListLayout) + findViewById(com.android.systemui.R.id.global_actions_view); + mGlobalActionsLayout.setOutsideTouchListener(view -> dismiss()); + mGlobalActionsLayout.setHasSeparatedView(mShouldDisplaySeparatedButton); + mGlobalActionsLayout.setListViewAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public boolean dispatchPopulateAccessibilityEvent( View host, AccessibilityEvent event) { @@ -1484,20 +1512,33 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return true; } }); + setTitle(R.string.global_actions); } private void updateList() { - mListView.removeAllViews(); - mSeparatedView.removeAllViews(); + mGlobalActionsLayout.removeAllItems(); + ArrayList<Action> separatedActions = + mAdapter.getSeparatedActions(mShouldDisplaySeparatedButton); + ArrayList<Action> listActions = mAdapter.getListActions(mShouldDisplaySeparatedButton); + mGlobalActionsLayout.setExpectedListItemCount(listActions.size()); + mGlobalActionsLayout.setExpectedSeparatedItemCount(separatedActions.size()); + for (int i = 0; i < mAdapter.getCount(); i++) { - ViewGroup parentView = mShouldDisplaySeparatedButton && i == mAdapter.getCount() - 1 - ? mSeparatedView : mListView; - View v = mAdapter.getView(i, null, parentView); + Action action = mAdapter.getItem(i); + int separatedIndex = separatedActions.indexOf(action); + ViewGroup parent; + if (separatedIndex != -1) { + parent = mGlobalActionsLayout.getParentView(true, separatedIndex); + } else { + int listIndex = listActions.indexOf(action); + parent = mGlobalActionsLayout.getParentView(false, listIndex); + } + View v = mAdapter.getView(i, null, parent); final int pos = i; v.setOnClickListener(view -> mClickListener.onClick(this, pos)); v.setOnLongClickListener(view -> mLongClickListener.onItemLongClick(null, v, pos, 0)); - parentView.addView(v); + parent.addView(v); } } @@ -1543,9 +1584,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, super.show(); mShowing = true; mGradientDrawable.setAlpha(0); - mHardwareLayout.setTranslationX(getAnimTranslation()); - mHardwareLayout.setAlpha(0); - mHardwareLayout.animate() + mGlobalActionsLayout.setTranslationX(getAnimTranslation()); + mGlobalActionsLayout.setAlpha(0); + mGlobalActionsLayout.animate() .alpha(1) .translationX(0) .setDuration(300) @@ -1564,9 +1605,9 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, return; } mShowing = false; - mHardwareLayout.setTranslationX(0); - mHardwareLayout.setAlpha(1); - mHardwareLayout.animate() + mGlobalActionsLayout.setTranslationX(0); + mGlobalActionsLayout.setAlpha(1); + mGlobalActionsLayout.animate() .alpha(0) .translationX(getAnimTranslation()) .setDuration(300) diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java index 5230cea88e8e..7ee37d567a55 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/SensorPrivacyTile.java @@ -84,7 +84,7 @@ public class SensorPrivacyTile extends QSTileImpl<BooleanState> implements @Override public Intent getLongClickIntent() { - return null; + return new Intent(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java index eea44906029d..839b06cec496 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java @@ -33,6 +33,13 @@ public interface NotificationEntryListener { default void onPendingEntryAdded(NotificationEntry entry) { } + // TODO: Combine this with onPreEntryUpdated into "onBeforeEntryFiltered" or similar + /** + * Called when a new entry is created but before it has been filtered or displayed to the user. + */ + default void onBeforeNotificationAdded(NotificationEntry entry) { + } + /** * Called when a new entry is created. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java index 45db00210a2e..989e781ab5ba 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java @@ -18,11 +18,9 @@ package com.android.systemui.statusbar.notification; import android.annotation.Nullable; import android.app.Notification; import android.content.Context; -import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -41,7 +39,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.NotificationInflater; import com.android.systemui.statusbar.notification.row.NotificationInflater.InflationFlag; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; @@ -68,8 +65,6 @@ public class NotificationEntryManager implements @VisibleForTesting protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>(); - private final DeviceProvisionedController mDeviceProvisionedController = - Dependency.get(DeviceProvisionedController.class); private final ForegroundServiceController mForegroundServiceController = Dependency.get(ForegroundServiceController.class); @@ -81,25 +76,12 @@ public class NotificationEntryManager implements private NotificationListenerService.RankingMap mLatestRankingMap; @VisibleForTesting protected NotificationData mNotificationData; - private NotificationListContainer mListContainer; + @VisibleForTesting final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders = new ArrayList<>(); private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>(); - private final DeviceProvisionedController.DeviceProvisionedListener - mDeviceProvisionedListener = - new DeviceProvisionedController.DeviceProvisionedListener() { - @Override - public void onDeviceProvisionedChanged() { - updateNotifications(); - } - }; - - public void destroy() { - mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener); - } - @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("NotificationEntryManager state:"); @@ -151,9 +133,6 @@ public class NotificationEntryManager implements HeadsUpManager headsUpManager) { mPresenter = presenter; mNotificationData.setHeadsUpManager(headsUpManager); - mListContainer = listContainer; - - mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); } /** Adds multiple {@link NotificationLifetimeExtender}s. */ @@ -227,7 +206,9 @@ public class NotificationEntryManager implements listener.onEntryInflated(entry, inflatedFlags); } mNotificationData.add(entry); - tagForeground(entry.notification); + for (NotificationEntryListener listener : mNotificationEntryListeners) { + listener.onBeforeNotificationAdded(entry); + } updateNotifications(); for (NotificationEntryListener listener : mNotificationEntryListeners) { listener.onNotificationAdded(entry); @@ -283,7 +264,6 @@ public class NotificationEntryManager implements if (entry.rowExists()) { entry.removeRow(); - mListContainer.cleanUpViewStateForEntry(entry); } // Let's remove the children if this was a summary @@ -368,19 +348,6 @@ public class NotificationEntryManager implements } } - @VisibleForTesting - void tagForeground(StatusBarNotification notification) { - ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps( - notification.getUserId(), notification.getPackageName()); - if (activeOps != null) { - int N = activeOps.size(); - for (int i = 0; i < N; i++) { - updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(), - notification.getPackageName(), true); - } - } - } - @Override public void addNotification(StatusBarNotification notification, NotificationListenerService.RankingMap ranking) { @@ -391,15 +358,6 @@ public class NotificationEntryManager implements } } - public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) { - String foregroundKey = mForegroundServiceController.getStandardLayoutKey( - UserHandle.getUserId(uid), pkg); - if (foregroundKey != null) { - mNotificationData.updateAppOp(appOp, uid, pkg, foregroundKey, showIcon); - updateNotifications(); - } - } - private void updateNotificationInternal(StatusBarNotification notification, NotificationListenerService.RankingMap ranking) throws InflationException { if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")"); @@ -452,8 +410,9 @@ public class NotificationEntryManager implements public void updateNotifications() { mNotificationData.filterAndSort(); - - mPresenter.updateNotificationViews(); + if (mPresenter != null) { + mPresenter.updateNotificationViews(); + } } public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java new file mode 100644 index 000000000000..88f4ca239af4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.util.ArraySet; + +import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.ForegroundServiceController; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; + +/** + * Root controller for the list of notifications in the shade. + * + * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy + * domain-specific behavior (ARC, etc) to subcontrollers. + */ +public class NotificationListController { + private final NotificationEntryManager mEntryManager; + private final NotificationListContainer mListContainer; + private final ForegroundServiceController mForegroundServiceController; + private final DeviceProvisionedController mDeviceProvisionedController; + + public NotificationListController( + NotificationEntryManager entryManager, + NotificationListContainer listContainer, + ForegroundServiceController foregroundServiceController, + DeviceProvisionedController deviceProvisionedController) { + mEntryManager = checkNotNull(entryManager); + mListContainer = checkNotNull(listContainer); + mForegroundServiceController = checkNotNull(foregroundServiceController); + mDeviceProvisionedController = checkNotNull(deviceProvisionedController); + } + + /** + * Causes the controller to register listeners on its dependencies. This method must be called + * before the controller is ready to perform its duties. + */ + public void bind() { + mEntryManager.addNotificationEntryListener(mEntryListener); + mDeviceProvisionedController.addCallback(mDeviceProvisionedListener); + } + + /** Should be called when the list controller is being destroyed. */ + public void destroy() { + mDeviceProvisionedController.removeCallback(mDeviceProvisionedListener); + } + + @SuppressWarnings("FieldCanBeLocal") + private final NotificationEntryListener mEntryListener = new NotificationEntryListener() { + @Override + public void onEntryRemoved( + NotificationEntry entry, + NotificationVisibility visibility, + boolean removedByUser) { + mListContainer.cleanUpViewStateForEntry(entry); + } + + @Override + public void onBeforeNotificationAdded(NotificationEntry entry) { + tagForeground(entry.notification); + } + }; + + private final DeviceProvisionedListener mDeviceProvisionedListener = + new DeviceProvisionedListener() { + @Override + public void onDeviceProvisionedChanged() { + mEntryManager.updateNotifications(); + } + }; + + // TODO: This method is horrifically inefficient + private void tagForeground(StatusBarNotification notification) { + ArraySet<Integer> activeOps = + mForegroundServiceController.getAppOps( + notification.getUserId(), notification.getPackageName()); + if (activeOps != null) { + int len = activeOps.size(); + for (int i = 0; i < len; i++) { + updateNotificationsForAppOp(activeOps.valueAt(i), notification.getUid(), + notification.getPackageName(), true); + } + } + } + + /** When an app op changes, propagate that change to notifications. */ + public void updateNotificationsForAppOp(int appOp, int uid, String pkg, boolean showIcon) { + String foregroundKey = + mForegroundServiceController.getStandardLayoutKey(UserHandle.getUserId(uid), pkg); + if (foregroundKey != null) { + mEntryManager + .getNotificationData().updateAppOp(appOp, uid, pkg, foregroundKey, showIcon); + mEntryManager.updateNotifications(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java index ebcd39b99778..323e7761b475 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationAssistantAction.java @@ -43,6 +43,11 @@ public class NavigationAssistantAction extends NavigationGestureAction { } @Override + public boolean disableProxyEvents() { + return true; + } + + @Override public void onGestureStart(MotionEvent event) { mAssistManager.startAssist(new Bundle()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java index 93605adf4589..7a42b03947ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBackAction.java @@ -95,6 +95,11 @@ public class NavigationBackAction extends NavigationGestureAction { } } + @Override + public boolean disableProxyEvents() { + return true; + } + private void performBack() { sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK); sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 31310f5f2043..32cc0e6d303a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -141,6 +141,7 @@ public class NotificationPanelView extends PanelView implements private KeyguardAffordanceHelper mAffordanceHelper; private KeyguardUserSwitcher mKeyguardUserSwitcher; private KeyguardStatusBarView mKeyguardStatusBar; + private ViewGroup mBigClockContainer; private QS mQs; private FrameLayout mQsFrame; @VisibleForTesting @@ -348,8 +349,8 @@ public class NotificationPanelView extends PanelView implements mKeyguardStatusView = findViewById(R.id.keyguard_status_view); KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container); - ViewGroup bigClockContainer = findViewById(R.id.big_clock_container); - keyguardClockSwitch.setBigClockContainer(bigClockContainer); + mBigClockContainer = findViewById(R.id.big_clock_container); + keyguardClockSwitch.setBigClockContainer(mBigClockContainer); mNotificationContainerParent = findViewById(R.id.notification_container_parent); mNotificationStackScroller = findViewById(R.id.notification_stack_scroller); @@ -585,6 +586,11 @@ public class NotificationPanelView extends PanelView implements mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock); PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y, mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock); + // Move big clock up while pulling up the bouncer + PropertyAnimator.setProperty(mBigClockContainer, AnimatableProperty.Y, + MathUtils.lerp(-mBigClockContainer.getHeight(), 0, + Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(getExpandedFraction())), + CLOCK_ANIMATION_PROPERTIES, animateClock); updateClock(); stackScrollerPadding = mClockPositionResult.stackScrollerPadding; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 853d7ab9a76d..3568f2846a51 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -612,9 +612,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo anim.setStartDelay(mAnimationDelay); anim.setDuration(mAnimationDuration); anim.addListener(new AnimatorListenerAdapter() { + private Callback lastCallback = mCallback; + @Override public void onAnimationEnd(Animator animation) { - onFinished(); + onFinished(lastCallback); scrim.setTag(TAG_KEY_ANIM, null); dispatchScrimsVisible(); @@ -672,14 +674,23 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo } private void onFinished() { + onFinished(mCallback); + } + + private void onFinished(Callback callback) { if (mWakeLockHeld) { mWakeLock.release(); mWakeLockHeld = false; } - if (mCallback != null) { - mCallback.onFinished(); - mCallback = null; + + if (callback != null) { + callback.onFinished(); + + if (callback == mCallback) { + mCallback = null; + } } + // When unlocking with fingerprint, we'll fade the scrims from black to transparent. // At the end of the animation we need to remove the tint. if (mState == ScrimState.UNLOCKED) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 7569a50a8c54..ed71598e22ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -196,6 +196,7 @@ import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationClicker; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; +import com.android.systemui.statusbar.notification.NotificationListController; import com.android.systemui.statusbar.notification.NotificationRowBinder; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -387,6 +388,7 @@ public class StatusBar extends SystemUI implements DemoMode, private NotificationGutsManager mGutsManager; protected NotificationLogger mNotificationLogger; protected NotificationEntryManager mEntryManager; + private NotificationListController mNotificationListController; private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private NotificationRowBinder mNotificationRowBinder; protected NotificationViewHierarchyManager mViewHierarchyManager; @@ -593,7 +595,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void onActiveStateChanged(int code, int uid, String packageName, boolean active) { mForegroundServiceController.onAppOpChanged(code, uid, packageName, active); Dependency.get(Dependency.MAIN_HANDLER).post(() -> { - mEntryManager.updateNotificationsForAppOp(code, uid, packageName, active); + mNotificationListController.updateNotificationsForAppOp(code, uid, packageName, active); }); } @@ -1044,6 +1046,13 @@ public class StatusBar extends SystemUI implements DemoMode, mScrimController, mActivityLaunchAnimator, mStatusBarKeyguardViewManager, mNotificationAlertingManager); + mNotificationListController = + new NotificationListController( + mEntryManager, + (NotificationListContainer) mStackScroller, + mForegroundServiceController, + mDeviceProvisionedController); + mAppOpsController.addCallback(APP_OPS, this); mNotificationListener.setUpWithPresenter(mPresenter); mNotificationShelf.setOnActivatedListener(mPresenter); @@ -1056,6 +1065,7 @@ public class StatusBar extends SystemUI implements DemoMode, this, Dependency.get(BubbleController.class), mNotificationActivityStarter)); mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager); + mNotificationListController.bind(); } /** @@ -2831,7 +2841,7 @@ public class StatusBar extends SystemUI implements DemoMode, } catch (RemoteException e) { // Ignore. } - mEntryManager.destroy(); + mNotificationListController.destroy(); // End old BaseStatusBar.destroy(). if (mStatusBarWindow != null) { mWindowManager.removeViewImmediate(mStatusBarWindow); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 04d24dc18f05..4f61009095c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -346,7 +346,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } private void handleFullScreenIntent(NotificationEntry entry) { - boolean isHeadsUped = mNotificationInterruptionStateProvider.canHeadsUpCommon(entry); + boolean isHeadsUped = mNotificationInterruptionStateProvider.shouldHeadsUp(entry); if (!isHeadsUped && entry.notification.getNotification().fullScreenIntent != null) { if (shouldSuppressFullScreenIntent(entry)) { if (DEBUG) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java index d937f93482d5..9ce6ae139998 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java @@ -22,19 +22,15 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; -import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -49,7 +45,6 @@ import android.service.notification.StatusBarNotification; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.util.ArraySet; import android.widget.FrameLayout; import com.android.internal.logging.MetricsLogger; @@ -79,8 +74,6 @@ import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.HeadsUpManager; -import junit.framework.Assert; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -346,7 +339,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase { verify(mEntryListener, never()).onInflationError(any(), any()); - verify(mListContainer).cleanUpViewStateForEntry(mEntry); verify(mPresenter).updateNotificationViews(); verify(mEntryListener).onEntryRemoved( mEntry, null, false /* removedByUser */); @@ -401,90 +393,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase { } @Test - public void testUpdateAppOps_foregroundNoti() { - com.android.systemui.util.Assert.isNotMainThread(); - - when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) - .thenReturn(mEntry.key); - mEntry.setRow(mRow); - mEntryManager.getNotificationData().add(mEntry); - - mEntryManager.updateNotificationsForAppOp( - AppOpsManager.OP_CAMERA, mEntry.notification.getUid(), - mEntry.notification.getPackageName(), true); - - verify(mPresenter, times(1)).updateNotificationViews(); - assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains( - AppOpsManager.OP_CAMERA)); - } - - @Test - public void testUpdateAppOps_otherNoti() { - com.android.systemui.util.Assert.isNotMainThread(); - - when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) - .thenReturn(null); - mEntryManager.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true); - - verify(mPresenter, never()).updateNotificationViews(); - } - - @Test - public void testAddNotificationExistingAppOps() { - mEntry.setRow(mRow); - mEntryManager.getNotificationData().add(mEntry); - ArraySet<Integer> expected = new ArraySet<>(); - expected.add(3); - expected.add(235); - expected.add(1); - - when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(), - mEntry.notification.getPackageName())).thenReturn(expected); - when(mForegroundServiceController.getStandardLayoutKey( - mEntry.notification.getUserId(), - mEntry.notification.getPackageName())).thenReturn(mEntry.key); - - mEntryManager.tagForeground(mEntry.notification); - - Assert.assertEquals(expected.size(), mEntry.mActiveAppOps.size()); - for (int op : expected) { - assertTrue("Entry missing op " + op, mEntry.mActiveAppOps.contains(op)); - } - } - - @Test - public void testAdd_noExistingAppOps() { - mEntry.setRow(mRow); - mEntryManager.getNotificationData().add(mEntry); - when(mForegroundServiceController.getStandardLayoutKey( - mEntry.notification.getUserId(), - mEntry.notification.getPackageName())).thenReturn(mEntry.key); - when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(), - mEntry.notification.getPackageName())).thenReturn(null); - - mEntryManager.tagForeground(mEntry.notification); - Assert.assertEquals(0, mEntry.mActiveAppOps.size()); - } - - @Test - public void testAdd_existingAppOpsNotForegroundNoti() { - mEntry.setRow(mRow); - mEntryManager.getNotificationData().add(mEntry); - ArraySet<Integer> ops = new ArraySet<>(); - ops.add(3); - ops.add(235); - ops.add(1); - when(mForegroundServiceController.getAppOps(mEntry.notification.getUserId(), - mEntry.notification.getPackageName())).thenReturn(ops); - when(mForegroundServiceController.getStandardLayoutKey( - mEntry.notification.getUserId(), - mEntry.notification.getPackageName())).thenReturn("something else"); - - mEntryManager.tagForeground(mEntry.notification); - Assert.assertEquals(0, mEntry.mActiveAppOps.size()); - } - - @Test public void testUpdateNotificationRanking() { when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true); when(mEnvironment.isDeviceProvisioned()).thenReturn(true); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java new file mode 100644 index 000000000000..4b5037bb3f64 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.app.Notification; +import android.os.UserHandle; +import android.service.notification.StatusBarNotification; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.ArraySet; + +import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.ForegroundServiceController; +import com.android.systemui.R; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.notification.collection.NotificationData; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class NotificationListControllerTest extends SysuiTestCase { + private NotificationListController mController; + + @Mock private NotificationEntryManager mEntryManager; + @Mock private NotificationListContainer mListContainer; + @Mock private ForegroundServiceController mForegroundServiceController; + @Mock private DeviceProvisionedController mDeviceProvisionedController; + + @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor; + @Captor private ArgumentCaptor<DeviceProvisionedListener> mProvisionedCaptor; + + private NotificationEntryListener mEntryListener; + private DeviceProvisionedListener mProvisionedListener; + + // TODO: Remove this once EntryManager no longer needs to be mocked + private NotificationData mNotificationData = new NotificationData(); + + private int mNextNotifId = 0; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + when(mEntryManager.getNotificationData()).thenReturn(mNotificationData); + + mController = new NotificationListController( + mEntryManager, + mListContainer, + mForegroundServiceController, + mDeviceProvisionedController); + mController.bind(); + + // Capture callbacks passed to mocks + verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture()); + mEntryListener = mEntryListenerCaptor.getValue(); + verify(mDeviceProvisionedController).addCallback(mProvisionedCaptor.capture()); + mProvisionedListener = mProvisionedCaptor.getValue(); + } + + @Test + public void testCleanUpViewStateOnEntryRemoved() { + final NotificationEntry entry = buildEntry(); + mEntryListener.onEntryRemoved( + entry, + NotificationVisibility.obtain(entry.key, 0, 0, true), + false); + verify(mListContainer).cleanUpViewStateForEntry(entry); + } + + @Test + public void testCallUpdateNotificationsOnDeviceProvisionedChange() { + mProvisionedListener.onDeviceProvisionedChanged(); + verify(mEntryManager).updateNotifications(); + } + + @Test + public void testAppOps_appOpAddedToForegroundNotif() { + // GIVEN a notification associated with a foreground service + final NotificationEntry entry = buildEntry(); + mNotificationData.add(entry); + when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) + .thenReturn(entry.key); + + // WHEN we are notified of a new app op + mController.updateNotificationsForAppOp( + AppOpsManager.OP_CAMERA, + entry.notification.getUid(), + entry.notification.getPackageName(), + true); + + // THEN the app op is added to the entry + assertTrue(entry.mActiveAppOps.contains(AppOpsManager.OP_CAMERA)); + // THEN updateNotifications() is called + verify(mEntryManager, times(1)).updateNotifications(); + } + + @Test + public void testAppOps_appOpAddedToUnrelatedNotif() { + // GIVEN No current foreground notifs + when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) + .thenReturn(null); + + // WHEN An unrelated notification gets a new app op + mController.updateNotificationsForAppOp(AppOpsManager.OP_CAMERA, 1000, "pkg", true); + + // THEN We never call updateNotifications() + verify(mEntryManager, never()).updateNotifications(); + } + + @Test + public void testAppOps_addNotificationWithExistingAppOps() { + // GIVEN a notification with three associated app ops that is associated with a foreground + // service + final NotificationEntry entry = buildEntry(); + mNotificationData.add(entry); + ArraySet<Integer> expected = new ArraySet<>(); + expected.add(3); + expected.add(235); + expected.add(1); + when(mForegroundServiceController.getStandardLayoutKey( + entry.notification.getUserId(), + entry.notification.getPackageName())).thenReturn(entry.key); + when(mForegroundServiceController.getAppOps(entry.notification.getUserId(), + entry.notification.getPackageName())).thenReturn(expected); + + // WHEN the notification is added + mEntryListener.onBeforeNotificationAdded(entry); + + // THEN the entry is tagged with all three app ops + assertEquals(expected.size(), entry.mActiveAppOps.size()); + for (int op : expected) { + assertTrue("Entry missing op " + op, entry.mActiveAppOps.contains(op)); + } + } + + @Test + public void testAdd_addNotificationWithNoExistingAppOps() { + // GIVEN a notification with NO associated app ops + final NotificationEntry entry = buildEntry(); + + mNotificationData.add(entry); + when(mForegroundServiceController.getStandardLayoutKey( + entry.notification.getUserId(), + entry.notification.getPackageName())).thenReturn(entry.key); + when(mForegroundServiceController.getAppOps(entry.notification.getUserId(), + entry.notification.getPackageName())).thenReturn(null); + + // WHEN the notification is added + mEntryListener.onBeforeNotificationAdded(entry); + + // THEN the entry doesn't have any app ops associated with it + assertEquals(0, entry.mActiveAppOps.size()); + } + + @Test + public void testAdd_addNonForegroundNotificationWithExistingAppOps() { + // GIVEN a notification with app ops that isn't associated with a foreground service + final NotificationEntry entry = buildEntry(); + mNotificationData.add(entry); + ArraySet<Integer> ops = new ArraySet<>(); + ops.add(3); + ops.add(235); + ops.add(1); + when(mForegroundServiceController.getAppOps(entry.notification.getUserId(), + entry.notification.getPackageName())).thenReturn(ops); + when(mForegroundServiceController.getStandardLayoutKey( + entry.notification.getUserId(), + entry.notification.getPackageName())).thenReturn("something else"); + + // WHEN the notification is added + mEntryListener.onBeforeNotificationAdded(entry); + + // THEN the entry doesn't have any app ops associated with it + assertEquals(0, entry.mActiveAppOps.size()); + } + + private NotificationEntry buildEntry() { + mNextNotifId++; + + Notification.Builder n = new Notification.Builder(mContext, "") + .setSmallIcon(R.drawable.ic_person) + .setContentTitle("Title") + .setContentText("Text"); + + StatusBarNotification notification = + new StatusBarNotification( + TEST_PACKAGE_NAME, + TEST_PACKAGE_NAME, + mNextNotifId, + null, + TEST_UID, + 0, + n.build(), + new UserHandle(ActivityManager.getCurrentUser()), + null, + 0); + return new NotificationEntry(notification); + } + + private static final String TEST_PACKAGE_NAME = "test"; + private static final int TEST_UID = 0; +} diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index a07411d0afaf..8261fe89f778 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -6814,6 +6814,12 @@ message MetricsEvent { // OS: Q SETTINGS_GESTURE_TAP_SCREEN = 1626; + // OPEN: Settings > Network & internet > Click Mobile network to land on a page with a list of + // SIM/eSIM subscriptions. + // CATEGORY: SETTINGS + // OS: Q + MOBILE_NETWORK_LIST = 1627; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index ec6d20dd5c6a..c992da43fc07 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -252,9 +252,8 @@ public final class AutofillManagerService @Override // from AbstractMasterSystemService protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId, boolean disabled) { - return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory, - mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, - disabled); + return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory, + mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled); } @Override // AbstractMasterSystemService @@ -291,6 +290,13 @@ public final class AutofillManagerService return mSupportedSmartSuggestionModes; } + /** + * Logs a request so it's dumped later... + */ + void logRequestLocked(@NonNull String historyItem) { + mRequestsHistory.log(historyItem); + } + // Called by AutofillManagerServiceImpl, doesn't need to check permission boolean isInstantServiceAllowed() { return mAllowInstantService; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index d037b081cd4d..954b67e4e2dc 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -108,7 +108,6 @@ final class AutofillManagerServiceImpl private static final Random sRandom = new Random(); - private final LocalLog mRequestsHistory; private final LocalLog mUiLatencyHistory; private final LocalLog mWtfHistory; private final FieldClassificationStrategy mFieldClassificationStrategy; @@ -166,12 +165,12 @@ final class AutofillManagerServiceImpl @Nullable private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService; - AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory, + AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui, - AutofillCompatState autofillCompatState, boolean disabled) { + AutofillCompatState autofillCompatState, + boolean disabled) { super(master, lock, userId); - mRequestsHistory = requestsHistory; mUiLatencyHistory = uiLatencyHistory; mWtfHistory = wtfHistory; mUi = ui; @@ -310,7 +309,7 @@ final class AutofillManagerServiceImpl + " s=" + mInfo.getServiceInfo().packageName + " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds + " hc=" + hasCallback + " f=" + flags; - mRequestsHistory.log(historyItem); + mMaster.logRequestLocked(historyItem); newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index a5ef21afc23e..7dfd8fef13c2 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2610,6 +2610,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState + " when server returned null for session " + this.id); } + final String historyItem = + "aug:id=" + id + " u=" + uid + " m=" + mode + + " a=" + ComponentName.flattenToShortString(mComponentName) + + " f=" + mCurrentViewId + + " s=" + remoteService.getComponentName(); + mService.getMaster().logRequestLocked(historyItem); + final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue(); // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index e0e81ffb6b48..79f8a7e4e9ae 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -494,20 +494,18 @@ public class UserBackupManagerService { mUserId); mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null"); - mBaseStateDir.mkdirs(); - if (!SELinux.restoreconRecursive(mBaseStateDir)) { - Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir); + // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE + // directory. Per-user CE directories are managed by vold. + if (userId == UserHandle.USER_SYSTEM) { + mBaseStateDir.mkdirs(); + if (!SELinux.restorecon(mBaseStateDir)) { + Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir); + } } + // TODO (b/120424138): The system user currently uses the cache which is managed by init.rc + // Initialization and restorecon is managed by vold for per-user CE directories. mDataDir = checkNotNull(dataDir, "dataDir cannot be null"); - // TODO(b/120424138): Remove when the system user moves out of the cache dir. The cache dir - // is managed by init.rc so we don't have to create it below. - if (userId != UserHandle.USER_SYSTEM) { - mDataDir.mkdirs(); - if (!SELinux.restoreconRecursive(mDataDir)) { - Slog.w(TAG, "SELinux restorecon failed on " + mDataDir); - } - } mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng); // Receivers for scheduled backups and transport initialization operations. diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java index 862ca711e694..cfc129e11c6e 100644 --- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java +++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java @@ -45,6 +45,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.SELinux; +import android.os.UserHandle; import android.os.WorkSource; import com.android.internal.annotations.GuardedBy; @@ -686,8 +687,12 @@ public class KeyValueBackupTask implements BackupRestoreTask, Runnable { ParcelFileDescriptor.open( mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE); - if (!SELinux.restorecon(mBackupDataFile)) { - mReporter.onRestoreconFailed(mBackupDataFile); + // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE + // directory. Per-user CE directories are managed by vold. + if (mUserId == UserHandle.USER_SYSTEM) { + if (!SELinux.restorecon(mBackupDataFile)) { + mReporter.onRestoreconFailed(mBackupDataFile); + } } IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.extractAgentData()"); diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java index dc0f6028b0f8..e4bbcd67d4df 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java @@ -32,6 +32,7 @@ import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.UserHandle; import android.os.UserManager; +import android.util.LocalLog; import android.util.Slog; import android.view.contentcapture.IContentCaptureManager; @@ -69,6 +70,8 @@ public final class ContentCaptureManagerService extends private final LocalService mLocalService = new LocalService(); + private final LocalLog mRequestsHistory = new LocalLog(20); + public ContentCaptureManagerService(@NonNull Context context) { super(context, new FrameworkResourcesServiceNameResolver(context, com.android.internal.R.string.config_defaultContentCaptureService), @@ -154,6 +157,13 @@ public final class ContentCaptureManagerService extends } } + /** + * Logs a request so it's dumped later... + */ + void logRequestLocked(@NonNull String historyItem) { + mRequestsHistory.log(historyItem); + } + private ActivityManagerInternal getAmInternal() { synchronized (mLock) { if (mAm == null) { @@ -217,9 +227,29 @@ public final class ContentCaptureManagerService extends public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; + boolean showHistory = true; + if (args != null) { + for (String arg : args) { + switch(arg) { + case "--no-history": + showHistory = false; + break; + case "--help": + pw.println("Usage: dumpsys content_capture [--no-history]"); + return; + default: + Slog.w(TAG, "Ignoring invalid dump arg: " + arg); + } + } + } + synchronized (mLock) { dumpLocked("", pw); } + if (showHistory) { + pw.println(); pw.println("Requests history:"); pw.println(); + mRequestsHistory.reverseDump(fd, pw, args); + } } @Override diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java index 1dae2ceae7d9..8d2c79bd9923 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java @@ -85,7 +85,6 @@ final class ContentCapturePerUserService ContentCapturePerUserService(@NonNull ContentCaptureManagerService master, @NonNull Object lock, boolean disabled, @UserIdInt int userId) { super(master, lock, userId); - updateRemoteServiceLocked(disabled); } @@ -170,14 +169,24 @@ final class ContentCapturePerUserService @NonNull ComponentName componentName, int taskId, int displayId, @NonNull String sessionId, int uid, int flags, @NonNull IResultReceiver clientReceiver) { - if (!isEnabledLocked()) { + + final ComponentName serviceComponentName = getServiceComponentName(); + final boolean enabled = isEnabledLocked(); + final String historyItem = + "id=" + sessionId + " uid=" + uid + + " a=" + ComponentName.flattenToShortString(componentName) + + " t=" + taskId + " d=" + displayId + + " s=" + ComponentName.flattenToShortString(serviceComponentName) + + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)"); + mMaster.logRequestLocked(historyItem); + + if (!enabled) { // TODO: it would be better to split in differet reasons, like // STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE, /* binder= */ null); return; } - final ComponentName serviceComponentName = getServiceComponentName(); if (serviceComponentName == null) { // TODO(b/111276913): this happens when the system service is starting, we should // probably handle it in a more elegant way (like waiting for boot_complete or diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java index ebe0083b398e..3c52e17ce1e8 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java +++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java @@ -83,6 +83,8 @@ final class ContentCaptureServerSession { */ @GuardedBy("mLock") public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) { + mService.getMaster().logRequestLocked("snapshot: id=" + mId); + mRemoteService.onActivitySnapshotRequest(mId, snapshotData); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d6f3e2ba4835..00550d9c660e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1494,6 +1494,9 @@ public class ConnectivityService extends IConnectivityManager.Stub newNc.setUids(null); newNc.setSSID(null); } + if (newNc.getNetworkSpecifier() != null) { + newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact()); + } return newNc; } @@ -5358,7 +5361,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } switch (notificationType) { case ConnectivityManager.CALLBACK_AVAILABLE: { - putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities)); + putParcelable(bundle, networkCapabilitiesRestrictedForCallerPermissions( + networkAgent.networkCapabilities, nri.mPid, nri.mUid)); putParcelable(bundle, new LinkProperties(networkAgent.linkProperties)); // For this notification, arg1 contains the blocked status. msg.arg1 = arg1; diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 1f9362e246b7..dc033691eea5 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -132,8 +132,11 @@ public final class OomAdjuster { mActiveUids = activeUids; mLocalPowerManager = LocalServices.getService(PowerManagerInternal.class); - mAppCompact = new AppCompactor(mService); mConstants = mService.mConstants; + // mConstants can be null under test, which causes AppCompactor to crash + if (mConstants != null) { + mAppCompact = new AppCompactor(mService); + } } /** diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 979de66f1dc8..669ff2b7bad5 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -138,6 +138,9 @@ public class InputManagerService extends IInputManager.Stub private final Context mContext; private final InputManagerHandler mHandler; + // Context cache used for loading pointer resources. + private Context mDisplayContext; + private final File mDoubleTouchGestureEnableFile; private WindowManagerCallbacks mWindowManagerCallbacks; @@ -1923,8 +1926,25 @@ public class InputManagerService extends IInputManager.Stub } // Native callback. - private PointerIcon getPointerIcon() { - return PointerIcon.getDefaultIcon(mContext); + private PointerIcon getPointerIcon(int displayId) { + return PointerIcon.getDefaultIcon(getContextForDisplay(displayId)); + } + + private Context getContextForDisplay(int displayId) { + if (mDisplayContext != null && mDisplayContext.getDisplay().getDisplayId() == displayId) { + return mDisplayContext; + } + + if (mContext.getDisplay().getDisplayId() == displayId) { + mDisplayContext = mContext; + return mDisplayContext; + } + + // Create and cache context for non-default display. + final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); + final Display display = displayManager.getDisplay(displayId); + mDisplayContext = mContext.createDisplayContext(display); + return mDisplayContext; } // Native callback. diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 16143d3ae9e0..74fbea1544bd 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -24,11 +24,14 @@ import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; import android.content.om.OverlayInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.os.Build.VERSION_CODES; import android.os.IBinder; import android.os.IIdmap2; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.os.UserHandle; import android.util.Slog; @@ -51,6 +54,13 @@ class IdmapManager { private final Installer mInstaller; private IIdmap2 mIdmap2Service; + private static final boolean VENDOR_IS_Q_OR_LATER; + static { + // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized + final String value = SystemProperties.get("ro.vndk.version", "Q"); + VENDOR_IS_Q_OR_LATER = value.equals("Q") || value.equals("q"); + } + IdmapManager(final Installer installer) { mInstaller = installer; if (FEATURE_FLAG_IDMAP2) { @@ -69,10 +79,13 @@ class IdmapManager { final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath(); try { if (FEATURE_FLAG_IDMAP2) { - if (mIdmap2Service.verifyIdmap(overlayPath, userId)) { + int policies = determineFulfilledPolicies(overlayPackage); + boolean enforce = enforceOverlayable(overlayPackage); + if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) { return true; } - return mIdmap2Service.createIdmap(targetPath, overlayPath, userId) != null; + return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce, + userId) != null; } else { mInstaller.idmap(targetPath, overlayPath, sharedGid); return true; @@ -156,4 +169,71 @@ class IdmapManager { }, SECOND_IN_MILLIS); } } + + /** + * Checks if overlayable and policies should be enforced on the specified overlay for backwards + * compatibility with pre-Q overlays. + */ + private boolean enforceOverlayable(@NonNull final PackageInfo overlayPackage) { + final ApplicationInfo ai = overlayPackage.applicationInfo; + if (ai.targetSdkVersion >= VERSION_CODES.Q) { + // Always enforce policies for overlays targeting Q+. + return true; + } + + if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) { + // If the overlay is on a pre-Q vendor partition, do not enforce overlayable + // restrictions on this overlay because the pre-Q platform has no understanding of + // overlayable. + return false; + } + + // Do not enforce overlayable restrictions on pre-Q overlays signed with the + // platform signature. + return !ai.isSignedWithPlatformKey(); + } + + /** + * Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills. + * @throws SecurityException if the overlay is not allowed to overlay any resource + */ + private int determineFulfilledPolicies(@NonNull final PackageInfo overlayPackage) + throws SecurityException { + final ApplicationInfo ai = overlayPackage.applicationInfo; + final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q; + + int fulfilledPolicies = 0; + + // TODO(b/119402606) : Add signature policy + + // Vendor partition (/vendor) + if (ai.isVendor()) { + if (overlayIsQOrLater) { + fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION; + } else if (VENDOR_IS_Q_OR_LATER) { + throw new SecurityException("Overlay must target Q sdk or higher"); + } + } + + // Product partition (/product) + if (ai.isProduct()) { + if (overlayIsQOrLater) { + fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION; + } else { + throw new SecurityException("Overlay must target Q sdk or higher"); + } + } + + // System partition (/system) + if (ai.isSystemApp()) { + if (overlayIsQOrLater) { + fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION; + } else { + throw new SecurityException("Overlay must target Q sdk or higher"); + } + } + + // All overlays can overlay resources with the public policy + return fulfilledPolicies | IIdmap2.POLICY_PUBLIC; + } } diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index b0d2704196a6..1cbf0bfac05c 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -270,7 +270,9 @@ final class OverlayManagerServiceImpl { Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId); } - updateAllOverlaysForTarget(packageName, userId, 0); + if (updateAllOverlaysForTarget(packageName, userId, 0)) { + mListener.onOverlaysChanged(packageName, userId); + } } void onTargetPackageRemoved(@NonNull final String packageName, final int userId) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 70ead41853d0..6fe32c5677d4 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -1343,6 +1343,7 @@ public class PackageManagerService extends IPackageManager.Stub final @Nullable String mWellbeingPackage; final @Nullable String mDocumenterPackage; final @Nullable String mConfiguratorPackage; + final @Nullable String mAppPredictionServicePackage; final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; @@ -2868,6 +2869,7 @@ public class PackageManagerService extends IPackageManager.Stub mDocumenterPackage = getDocumenterPackageName(); mConfiguratorPackage = mContext.getString(R.string.config_deviceConfiguratorPackageName); + mAppPredictionServicePackage = getAppPredictionServicePackageName(); // Now that we know all of the shared libraries, update all clients to have // the correct library paths. @@ -3750,7 +3752,7 @@ public class PackageManagerService extends IPackageManager.Stub /** * Returns whether or not a full application can see an instant application. * <p> - * Currently, there are three cases in which this can occur: + * Currently, there are four cases in which this can occur: * <ol> * <li>The calling application is a "special" process. Special processes * are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li> @@ -3758,6 +3760,7 @@ public class PackageManagerService extends IPackageManager.Stub * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li> * <li>The calling application is the default launcher on the * system partition.</li> + * <li>The calling application is the default app prediction service.</li> * </ol> */ private boolean canViewInstantApps(int callingUid, int userId) { @@ -3775,6 +3778,11 @@ public class PackageManagerService extends IPackageManager.Stub && isCallerSameApp(homeComponent.getPackageName(), callingUid)) { return true; } + // TODO(b/122900055) Change/Remove this and replace with new permission role. + if (mAppPredictionServicePackage != null + && isCallerSameApp(mAppPredictionServicePackage, callingUid)) { + return true; + } } return false; } @@ -5490,13 +5498,13 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUserId = UserHandle.getUserId(callingUid); final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; // Map to base uids. - uid1 = UserHandle.getAppId(uid1); - uid2 = UserHandle.getAppId(uid2); + final int appId1 = UserHandle.getAppId(uid1); + final int appId2 = UserHandle.getAppId(uid2); // reader synchronized (mPackages) { Signature[] s1; Signature[] s2; - Object obj = mSettings.getSettingLPr(uid1); + Object obj = mSettings.getSettingLPr(appId1); if (obj != null) { if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { @@ -5515,7 +5523,7 @@ public class PackageManagerService extends IPackageManager.Stub } else { return PackageManager.SIGNATURE_UNKNOWN_PACKAGE; } - obj = mSettings.getSettingLPr(uid2); + obj = mSettings.getSettingLPr(appId2); if (obj != null) { if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { @@ -5570,11 +5578,11 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUid = Binder.getCallingUid(); final int callingUserId = UserHandle.getUserId(callingUid); // Map to base uids. - uid = UserHandle.getAppId(uid); + final int appId = UserHandle.getAppId(uid); // reader synchronized (mPackages) { final PackageParser.SigningDetails signingDetails; - final Object obj = mSettings.getSettingLPr(uid); + final Object obj = mSettings.getSettingLPr(appId); if (obj != null) { if (obj instanceof SharedUserSetting) { final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; @@ -5690,10 +5698,10 @@ public class PackageManagerService extends IPackageManager.Stub final int callingUid = Binder.getCallingUid(); final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; final int userId = UserHandle.getUserId(uid); - uid = UserHandle.getAppId(uid); + final int appId = UserHandle.getAppId(uid); // reader synchronized (mPackages) { - Object obj = mSettings.getSettingLPr(uid); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { if (isCallerInstantApp) { return null; @@ -5728,8 +5736,9 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return null; } + final int appId = UserHandle.getAppId(uid); synchronized (mPackages) { - Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.name + ":" + sus.userId; @@ -5756,8 +5765,8 @@ public class PackageManagerService extends IPackageManager.Stub final String[] names = new String[uids.length]; synchronized (mPackages) { for (int i = uids.length - 1; i >= 0; i--) { - final int uid = uids[i]; - Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); + final int appId = UserHandle.getAppId(uids[i]); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; names[i] = "shared:" + sus.name; @@ -5805,8 +5814,9 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return 0; } + final int appId = UserHandle.getAppId(uid); synchronized (mPackages) { - Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.pkgFlags; @@ -5827,8 +5837,9 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { return 0; } + final int appId = UserHandle.getAppId(uid); synchronized (mPackages) { - Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid)); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; return sus.pkgPrivateFlags; @@ -5848,10 +5859,10 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(Binder.getCallingUid()) != null) { return false; } - uid = UserHandle.getAppId(uid); + final int appId = UserHandle.getAppId(uid); // reader synchronized (mPackages) { - Object obj = mSettings.getSettingLPr(uid); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; final Iterator<PackageSetting> it = sus.packages.iterator(); @@ -13781,6 +13792,11 @@ public class PackageManagerService extends IPackageManager.Stub ServiceManager.getService(Context.BACKUP_SERVICE)); if (bm != null) { int userId = args.user.getIdentifier(); + // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM + // in the BackupManager. USER_ALL is used in compatibility tests. + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + } if (DEBUG_INSTALL) { Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId); } @@ -18947,7 +18963,8 @@ public class PackageManagerService extends IPackageManager.Stub @GuardedBy("mPackages") private int getUidTargetSdkVersionLockedLPr(int uid) { - Object obj = mSettings.getSettingLPr(uid); + final int appId = UserHandle.getAppId(uid); + final Object obj = mSettings.getSettingLPr(appId); if (obj instanceof SharedUserSetting) { final SharedUserSetting sus = (SharedUserSetting) obj; int vers = Build.VERSION_CODES.CUR_DEVELOPMENT; @@ -19138,7 +19155,7 @@ public class PackageManagerService extends IPackageManager.Stub // writer synchronized (mPackages) { PackageParser.Package pkg = mPackages.get(packageName); - if (pkg == null || pkg.applicationInfo.uid != callingUid) { + if (pkg == null || !isCallerSameApp(packageName, callingUid)) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.SET_PREFERRED_APPLICATIONS) != PackageManager.PERMISSION_GRANTED) { @@ -19811,6 +19828,14 @@ public class PackageManagerService extends IPackageManager.Stub .setPackage(launcherComponent.getPackageName()); mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid)); } + // TODO(b/122900055) Change/Remove this and replace with new permission role. + if (mAppPredictionServicePackage != null) { + Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED) + .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo) + .putExtra(Intent.EXTRA_USER, UserHandle.of(userId)) + .setPackage(mAppPredictionServicePackage); + mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid)); + } } } @@ -19963,6 +19988,20 @@ public class PackageManagerService extends IPackageManager.Stub return mContext.getString(R.string.config_defaultWellbeingPackage); } + private String getAppPredictionServicePackageName() { + String flattenedAppPredictionServiceComponentName = + mContext.getString(R.string.config_defaultAppPredictionService); + if (flattenedAppPredictionServiceComponentName == null) { + return null; + } + ComponentName appPredictionServiceComponentName = + ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName); + if (appPredictionServiceComponentName == null) { + return null; + } + return appPredictionServiceComponentName.getPackageName(); + } + @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId, String callingPackage) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 95da2091828d..b0f232607d88 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2790,13 +2790,13 @@ public final class Settings { // dataPath - path to package's data path // seinfo - seinfo label for the app (assigned at install time) // gids - supplementary gids this app launches with + // profileableFromShellFlag - 0 or 1 if the package is profileable from shell. // // NOTE: We prefer not to expose all ApplicationInfo flags for now. // // DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS // FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES: - // frameworks/base/libs/packagelistparser - // system/core/run-as/run-as.c + // system/core/libpackagelistparser // sb.setLength(0); sb.append(ai.packageName); @@ -2816,6 +2816,8 @@ public final class Settings { } else { sb.append("none"); } + sb.append(" "); + sb.append(ai.isProfileableByShell() ? "1" : "0"); sb.append("\n"); writer.append(sb); } diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 83f0fde066ec..563fd7f90c4b 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -20,8 +20,10 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; import android.content.res.Resources; import android.os.PersistableBundle; import android.text.format.Formatter; @@ -640,6 +642,55 @@ class ShortcutPackage extends ShortcutPackageItem { } /** + * Returns a list of ShortcutInfos that match the given intent filter and the category of + * available ShareTarget definitions in this package. + */ + public List<ShortcutManager.ShareShortcutInfo> getMatchingShareTargets( + @NonNull IntentFilter filter) { + final List<ShareTargetInfo> matchedTargets = new ArrayList<>(); + for (int i = 0; i < mShareTargets.size(); i++) { + final ShareTargetInfo target = mShareTargets.get(i); + for (ShareTargetInfo.TargetData data : target.mTargetData) { + if (filter.hasDataType(data.mMimeType)) { + // Matched at least with one data type + matchedTargets.add(target); + break; + } + } + } + + if (matchedTargets.isEmpty()) { + return new ArrayList<>(); + } + + // Get the list of all dynamic shortcuts in this package + final ArrayList<ShortcutInfo> shortcuts = new ArrayList<>(); + findAll(shortcuts, ShortcutInfo::isDynamicVisible, ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER); + + final List<ShortcutManager.ShareShortcutInfo> result = new ArrayList<>(); + for (int i = 0; i < shortcuts.size(); i++) { + final ShortcutInfo si = shortcuts.get(i); + for (int j = 0; j < matchedTargets.size(); j++) { + // Shortcut must have all of share target categories + boolean hasAllCategories = true; + final ShareTargetInfo target = matchedTargets.get(j); + for (int q = 0; q < target.mCategories.length; q++) { + if (!si.getCategories().contains(target.mCategories[q])) { + hasAllCategories = false; + break; + } + } + if (hasAllCategories) { + result.add(new ShortcutManager.ShareShortcutInfo(si, new ComponentName( + getPackageName(), target.mTargetClass))); + break; + } + } + } + return result; + } + + /** * Return the filenames (excluding path names) of icon bitmap files from this package. */ public ArraySet<String> getUsedBitmapFiles() { diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 2b773f47e3e9..fdbaba24966b 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -46,6 +46,7 @@ import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; import android.content.pm.ShortcutServiceInternal; import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener; import android.content.res.Resources; @@ -2149,6 +2150,23 @@ public class ShortcutService extends IShortcutService.Stub { } } + @Override + public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName, + IntentFilter filter, @UserIdInt int userId) { + verifyCaller(packageName, userId); + + synchronized (mLock) { + throwIfUserLockedL(userId); + + final List<ShortcutManager.ShareShortcutInfo> shortcutInfoList = new ArrayList<>(); + + final ShortcutUser user = getUserShortcutsLocked(userId); + user.forAllPackages(p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter))); + + return new ParceledListSlice<>(shortcutInfoList); + } + } + @GuardedBy("mLock") private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName, @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index ff93345a6e8d..41cab2d7ebd3 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -480,6 +480,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int mShortPressOnSleepBehavior; int mShortPressOnWindowBehavior; boolean mHasSoftInput = false; + boolean mHapticTextHandleEnabled; boolean mUseTvRouting; int mVeryLongPressTimeout; boolean mAllowStartActivityForLongPressOnPowerDuringSetup; @@ -1836,6 +1837,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { mAllowStartActivityForLongPressOnPowerDuringSetup = mContext.getResources().getBoolean( com.android.internal.R.bool.config_allowStartActivityForLongPressOnPowerInSetup); + mHapticTextHandleEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enableHapticTextHandle); + mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION; mHandleVolumeKeysInWM = mContext.getResources().getBoolean( @@ -2291,9 +2295,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } final LayoutParams attrs = win.getAttrs(); - final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw() && - ((imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0 - || !canBeHiddenByKeyguardLw(imeTarget)); + final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleLw() + && (imeTarget.canShowWhenLocked() || !canBeHiddenByKeyguardLw(imeTarget)); // Show IME over the keyguard if the target allows it boolean allowWhenLocked = (win.isInputMethodWindow() || imeTarget == this) @@ -2301,7 +2304,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isKeyguardLocked() && isKeyguardOccluded()) { // Show SHOW_WHEN_LOCKED windows if Keyguard is occluded. - allowWhenLocked |= (attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 + allowWhenLocked |= win.canShowWhenLocked() // Show error dialogs over apps that are shown on lockscreen || (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0; } @@ -5201,8 +5204,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { case HapticFeedbackConstants.CLOCK_TICK: case HapticFeedbackConstants.CONTEXT_CLICK: return VibrationEffect.get(VibrationEffect.EFFECT_TICK); - case HapticFeedbackConstants.KEYBOARD_RELEASE: case HapticFeedbackConstants.TEXT_HANDLE_MOVE: + if (!mHapticTextHandleEnabled) { + return null; + } + case HapticFeedbackConstants.KEYBOARD_RELEASE: case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE: case HapticFeedbackConstants.ENTRY_BUMP: case HapticFeedbackConstants.DRAG_CROSSING: @@ -5367,11 +5373,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.println(mAllowStartActivityForLongPressOnPowerDuringSetup); pw.print(prefix); pw.print("mHasSoftInput="); pw.print(mHasSoftInput); - pw.print(" mDismissImeOnBackKeyPressed="); pw.println(mDismissImeOnBackKeyPressed); + pw.print(" mHapticTextHandleEnabled="); pw.println(mHapticTextHandleEnabled); + pw.print(prefix); + pw.print("mDismissImeOnBackKeyPressed="); pw.print(mDismissImeOnBackKeyPressed); + pw.print(" mIncallPowerBehavior="); + pw.println(incallPowerBehaviorToString(mIncallPowerBehavior)); pw.print(prefix); - pw.print("mIncallPowerBehavior="); - pw.print(incallPowerBehaviorToString(mIncallPowerBehavior)); - pw.print(" mIncallBackBehavior="); + pw.print("mIncallBackBehavior="); pw.print(incallBackBehaviorToString(mIncallBackBehavior)); pw.print(" mEndcallBehavior="); pw.println(endcallBehaviorToString(mEndcallBehavior)); diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index c37254b22ea5..e1a911e8ada5 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -468,6 +468,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { /** @return true if this window desires key events. */ boolean canReceiveKeys(); + /** @return true if the window can show over keyguard. */ + boolean canShowWhenLocked(); + /** * Writes {@link com.android.server.wm.IdentifierProto} to stream. */ diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java index 45c975b26956..055c941f8b0a 100644 --- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java +++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java @@ -62,6 +62,8 @@ public class LegacyRoleResolutionPolicy implements RoleManagerService.RoleHolder mContext.getContentResolver(), Settings.Secure.SMS_DEFAULT_APPLICATION, userId); + // TODO: STOPSHIP: Remove the following code once we remove default_sms_application + // and use the new config_defaultRoleHolders. if (result == null) { Collection<SmsApplication.SmsApplicationData> applications = SmsApplication.getApplicationCollectionAsUser(mContext, userId); diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index c0ec3672c665..5516b234925b 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -229,9 +229,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C // Any role for which we have a record are already migrated RoleUserState userState = getOrCreateUserState(userId); if (!userState.isRoleAvailable(role)) { - userState.addRoleName(role); List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId); + if (roleHolders.isEmpty()) { + return; + } Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders); + userState.addRoleName(role); int size = roleHolders.size(); for (int i = 0; i < size; i++) { userState.addRoleHolder(role, roleHolders.get(i)); diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 9f8af5048da2..b8634d88319a 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2508,6 +2508,13 @@ final class ActivityRecord extends ConfigurationContainer { final IBinder binder = (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null; mAppWindowToken.setOrientation(requestedOrientation, binder, this); + + // Push the new configuration to the requested app in case where it's not pushed, e.g. when + // the request is handled at task level with letterbox. + if (!getMergedOverrideConfiguration().equals( + mLastReportedConfiguration.getMergedConfiguration())) { + ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); + } } int getOrientation() { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index a4cda5aac895..3a288ca5560d 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -2641,6 +2641,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { try { mService.moveTaskToFrontLocked(task.taskId, 0, options, true /* fromRecents */); + // Apply options to prevent pendingOptions be taken by client to make sure + // the override pending app transition will be applied immediately. + targetActivity.applyOptionsLocked(); } finally { mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, targetActivity); diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b735115be61e..6527ca0e751d 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -328,14 +328,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED; /** - * Flag indicating that the application is receiving an orientation that has different metrics - * than it expected. E.g. Portrait instead of Landscape. - * - * @see #updateRotationUnchecked() - */ - private boolean mAltOrientation = false; - - /** * Orientation forced by some window. If there is no visible window that specifies orientation * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}. * @@ -1085,10 +1077,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return mLastOrientation; } - boolean getAltOrientation() { - return mAltOrientation; - } - int getLastWindowForcedOrientation() { return mLastWindowForcedOrientation; } @@ -1130,15 +1118,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo boolean rotationNeedsUpdate() { final int lastOrientation = getLastOrientation(); final int oldRotation = getRotation(); - final boolean oldAltOrientation = getAltOrientation(); final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation); - final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics( - lastOrientation, rotation); - if (oldRotation == rotation && oldAltOrientation == altOrientation) { - return false; - } - return true; + return oldRotation != rotation; } /** @@ -1336,7 +1318,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final int oldRotation = mRotation; final int lastOrientation = mLastOrientation; - final boolean oldAltOrientation = mAltOrientation; final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation); if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id=" + mDisplayId + " based on lastOrientation=" + lastOrientation @@ -1368,35 +1349,26 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } final boolean rotateSeamlessly = mayRotateSeamlessly; - // TODO: Implement forced rotation changes. - // Set mAltOrientation to indicate that the application is receiving - // an orientation that has different metrics than it expected. - // eg. Portrait instead of Landscape. - - final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics( - lastOrientation, rotation); - if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId + " selected orientation " + lastOrientation + ", got rotation " + rotation + " which has " - + (altOrientation ? "incompatible" : "compatible") + " metrics"); + + " metrics"); - if (oldRotation == rotation && oldAltOrientation == altOrientation) { + if (oldRotation == rotation) { // No change. return false; } if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId + " rotation changed to " + rotation - + (altOrientation ? " (alt)" : "") + " from " + oldRotation - + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation); + + " from " + oldRotation + + ", lastOrientation=" + lastOrientation); if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) { mWaitingForConfig = true; } mRotation = rotation; - mAltOrientation = altOrientation; mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE; mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT, @@ -1538,26 +1510,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private DisplayInfo updateDisplayAndOrientation(int uiMode) { // Use the effective "visual" dimensions based on current rotation final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270); - final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; - final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; - int dw = realdw; - int dh = realdh; - - if (mAltOrientation) { - if (realdw > realdh) { - // Turn landscape into portrait. - int maxw = (int)(realdh/1.3f); - if (maxw < realdw) { - dw = maxw; - } - } else { - // Turn portrait into landscape. - int maxh = (int)(realdw/1.3f); - if (maxh < realdh) { - dh = maxh; - } - } - } + final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; + final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; // Update application display metrics. final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation); diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 7aabc15d9860..bc165dceb544 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -676,36 +676,6 @@ public class DisplayRotation { return rotation == mPortraitRotation || rotation == mUpsideDownRotation; } - /** - * Given an orientation constant and a rotation, returns true if the rotation - * has compatible metrics to the requested orientation. For example, if - * the application requested landscape and got seascape, then the rotation - * has compatible metrics; if the application requested portrait and got landscape, - * then the rotation has incompatible metrics; if the application did not specify - * a preference, then anything goes. - * - * @param orientation An orientation constant, such as - * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}. - * @param rotation The rotation to check. - * @return True if the rotation is compatible with the requested orientation. - */ - boolean rotationHasCompatibleMetrics(int orientation, int rotation) { - switch (orientation) { - case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: - case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: - case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: - return isAnyPortrait(rotation); - - case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: - case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: - case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: - return isLandscapeOrSeascape(rotation); - - default: - return true; - } - } - private boolean isValidRotationChoice(final int preferredRotation) { // Determine if the given app orientation is compatible with the provided rotation choice. switch (mCurrentAppOrientation) { diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java index 55554a716478..9b7214120aed 100644 --- a/services/core/java/com/android/server/wm/RootActivityContainer.java +++ b/services/core/java/com/android/server/wm/RootActivityContainer.java @@ -234,7 +234,7 @@ class RootActivityContainer extends ConfigurationContainer mWindowManager = wm; setWindowContainer(mWindowManager.mRoot); mDisplayManager = mService.mContext.getSystemService(DisplayManager.class); - mDisplayManager.registerDisplayListener(this, mService.mH); + mDisplayManager.registerDisplayListener(this, mService.mUiHandler); mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); final Display[] displays = mDisplayManager.getDisplays(); diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java index 905787051de8..2e5df45f9080 100644 --- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java +++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java @@ -31,6 +31,10 @@ import android.view.WindowManagerPolicyConstants.PointerEventListener; import com.android.server.wm.WindowManagerService.H; +/** + * 1. Adjust the top most focus display if touch down on some display. + * 2. Adjust the pointer icon when cursor moves to the task bounds. + */ public class TaskTapPointerEventListener implements PointerEventListener { private final Region mTouchExcludeRegion = new Region(); @@ -80,8 +84,7 @@ public class TaskTapPointerEventListener implements PointerEventListener { if (motionEvent.getDisplayId() != getDisplayId()) { return; } - final int action = motionEvent.getAction(); - switch (action & MotionEvent.ACTION_MASK) { + switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { final int x = (int) motionEvent.getX(); final int y = (int) motionEvent.getY(); @@ -97,7 +100,7 @@ public class TaskTapPointerEventListener implements PointerEventListener { } } break; - + case MotionEvent.ACTION_HOVER_ENTER: case MotionEvent.ACTION_HOVER_MOVE: { final int x = (int) motionEvent.getX(); final int y = (int) motionEvent.getY(); @@ -125,6 +128,7 @@ public class TaskTapPointerEventListener implements PointerEventListener { mPointerIconType = iconType; if (mPointerIconType == TYPE_NOT_SPECIFIED) { // Find the underlying window and ask it restore the pointer icon. + mService.mH.removeMessages(H.RESTORE_POINTER_ICON); mService.mH.obtainMessage(H.RESTORE_POINTER_ICON, x, y, mDisplayContent).sendToTarget(); } else { @@ -133,6 +137,18 @@ public class TaskTapPointerEventListener implements PointerEventListener { } } break; + case MotionEvent.ACTION_HOVER_EXIT: { + final int x = (int) motionEvent.getX(); + final int y = (int) motionEvent.getY(); + if (mPointerIconType != TYPE_NOT_SPECIFIED) { + mPointerIconType = TYPE_NOT_SPECIFIED; + // Find the underlying window and ask it to restore the pointer icon. + mService.mH.removeMessages(H.RESTORE_POINTER_ICON); + mService.mH.obtainMessage(H.RESTORE_POINTER_ICON, + x, y, mDisplayContent).sendToTarget(); + } + } + break; } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 0c4f4961d215..fda7a85c1270 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5943,8 +5943,6 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" apps="); pw.print(mAppsFreezingScreen); final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked(); pw.print(" mRotation="); pw.print(defaultDisplayContent.getRotation()); - pw.print(" mAltOrientation="); - pw.println(defaultDisplayContent.getAltOrientation()); pw.print(" mLastWindowForcedOrientation="); pw.print(defaultDisplayContent.getLastWindowForcedOrientation()); pw.print(" mLastOrientation="); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index cd29b3c29248..8f86c003e4b0 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2405,6 +2405,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP && !cantReceiveTouchInput(); } + @Override + public boolean canShowWhenLocked() { + final boolean showBecauseOfActivity = + mAppToken != null && mAppToken.mActivityRecord.canShowWhenLocked(); + final boolean showBecauseOfWindow = (getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0; + return showBecauseOfActivity || showBecauseOfWindow; + } + /** @return false if this window desires touch events. */ boolean cantReceiveTouchInput() { return mAppToken != null && mAppToken.getTask() != null diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 641200769cf0..90c9cc2b0a35 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -111,6 +111,7 @@ static struct { jmethodID getKeyboardLayoutOverlay; jmethodID getDeviceAlias; jmethodID getTouchCalibrationForInputDevice; + jmethodID getContextForDisplay; } gServiceClassInfo; static struct { @@ -260,17 +261,16 @@ public: /* --- PointerControllerPolicyInterface implementation --- */ - virtual void loadPointerIcon(SpriteIcon* icon); - virtual void loadPointerResources(PointerResources* outResources); + virtual void loadPointerIcon(SpriteIcon* icon, int32_t displayId); + virtual void loadPointerResources(PointerResources* outResources, int32_t displayId); virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, - std::map<int32_t, PointerAnimation>* outAnimationResources); + std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId); virtual int32_t getDefaultPointerIconId(); virtual int32_t getCustomPointerIconId(); private: sp<InputManager> mInputManager; - jobject mContextObj; jobject mServiceObj; sp<Looper> mLooper; @@ -329,7 +329,6 @@ NativeInputManager::NativeInputManager(jobject contextObj, mLooper(looper), mInteractive(true) { JNIEnv* env = jniEnv(); - mContextObj = env->NewGlobalRef(contextObj); mServiceObj = env->NewGlobalRef(serviceObj); { @@ -351,7 +350,6 @@ NativeInputManager::NativeInputManager(jobject contextObj, NativeInputManager::~NativeInputManager() { JNIEnv* env = jniEnv(); - env->DeleteGlobalRef(mContextObj); env->DeleteGlobalRef(mServiceObj); } @@ -1202,19 +1200,22 @@ bool NativeInputManager::checkInjectEventsPermissionNonReentrant( return result; } -void NativeInputManager::loadPointerIcon(SpriteIcon* icon) { +void NativeInputManager::loadPointerIcon(SpriteIcon* icon, int32_t displayId) { ATRACE_CALL(); JNIEnv* env = jniEnv(); ScopedLocalRef<jobject> pointerIconObj(env, env->CallObjectMethod( - mServiceObj, gServiceClassInfo.getPointerIcon)); + mServiceObj, gServiceClassInfo.getPointerIcon, displayId)); if (checkAndClearExceptionFromCallback(env, "getPointerIcon")) { return; } + ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod( + mServiceObj, gServiceClassInfo.getContextForDisplay, displayId)); + PointerIcon pointerIcon; status_t status = android_view_PointerIcon_load(env, pointerIconObj.get(), - mContextObj, &pointerIcon); + displayContext.get(), &pointerIcon); if (!status && !pointerIcon.isNullIcon()) { *icon = SpriteIcon(pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY); } else { @@ -1222,28 +1223,34 @@ void NativeInputManager::loadPointerIcon(SpriteIcon* icon) { } } -void NativeInputManager::loadPointerResources(PointerResources* outResources) { +void NativeInputManager::loadPointerResources(PointerResources* outResources, int32_t displayId) { ATRACE_CALL(); JNIEnv* env = jniEnv(); - loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_HOVER, + ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod( + mServiceObj, gServiceClassInfo.getContextForDisplay, displayId)); + + loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_HOVER, &outResources->spotHover); - loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_TOUCH, + loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_TOUCH, &outResources->spotTouch); - loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_SPOT_ANCHOR, + loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_SPOT_ANCHOR, &outResources->spotAnchor); } void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, - std::map<int32_t, PointerAnimation>* outAnimationResources) { + std::map<int32_t, PointerAnimation>* outAnimationResources, int32_t displayId) { ATRACE_CALL(); JNIEnv* env = jniEnv(); + ScopedLocalRef<jobject> displayContext(env, env->CallObjectMethod( + mServiceObj, gServiceClassInfo.getContextForDisplay, displayId)); + for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING; ++iconId) { PointerIcon pointerIcon; loadSystemIconAsSpriteWithPointerIcon( - env, mContextObj, iconId, &pointerIcon, &((*outResources)[iconId])); + env, displayContext.get(), iconId, &pointerIcon, &((*outResources)[iconId])); if (!pointerIcon.bitmapFrames.empty()) { PointerAnimation& animationData = (*outAnimationResources)[iconId]; size_t numFrames = pointerIcon.bitmapFrames.size() + 1; @@ -1258,7 +1265,7 @@ void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIc } } } - loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL, + loadSystemIconAsSprite(env, displayContext.get(), POINTER_ICON_STYLE_NULL, &((*outResources)[POINTER_ICON_STYLE_NULL])); } @@ -1819,7 +1826,7 @@ int register_android_server_InputManager(JNIEnv* env) { "getPointerLayer", "()I"); GET_METHOD_ID(gServiceClassInfo.getPointerIcon, clazz, - "getPointerIcon", "()Landroid/view/PointerIcon;"); + "getPointerIcon", "(I)Landroid/view/PointerIcon;"); GET_METHOD_ID(gServiceClassInfo.getPointerDisplayId, clazz, "getPointerDisplayId", "()I"); @@ -1835,6 +1842,10 @@ int register_android_server_InputManager(JNIEnv* env) { "getTouchCalibrationForInputDevice", "(Ljava/lang/String;I)Landroid/hardware/input/TouchCalibration;"); + GET_METHOD_ID(gServiceClassInfo.getContextForDisplay, clazz, + "getContextForDisplay", + "(I)Landroid/content/Context;") + // InputDevice FIND_CLASS(gInputDeviceClassInfo.clazz, "android/view/InputDevice"); diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 1f5c64e92ac0..bc1f7981258d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -42,6 +42,7 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.IUidObserver; +import android.app.Person; import android.app.usage.UsageStatsManagerInternal; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; @@ -1588,6 +1589,14 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } /** + * Make a Person. + */ + protected Person makePerson(CharSequence name, String key, String uri) { + final Person.Builder builder = new Person.Builder(); + return builder.setName(name).setKey(key).setUri(uri).build(); + } + + /** * Make an component name, with the client context. */ @NonNull diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 9b59f9151fd0..8d0365b534b5 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -248,6 +248,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setRank(123) + .setPerson(makePerson("person", "personKey", "personUri")) + .setLongLived() .setExtras(pb) .build(); si.addFlags(ShortcutInfo.FLAG_PINNED); @@ -267,9 +269,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getRank()); + assertEquals("person", si.getPersons()[0].getName()); + assertEquals("personKey", si.getPersons()[0].getKey()); + assertEquals("personUri", si.getPersons()[0].getUri()); assertEquals(1, si.getExtras().getInt("k")); - assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals("abc", si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); @@ -345,6 +350,8 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) .setRank(123) + .setPerson(makePerson("person", "personKey", "personUri")) + .setLongLived() .setExtras(pb) .build(); sorig.addFlags(ShortcutInfo.FLAG_PINNED); @@ -368,9 +375,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getRank()); + assertEquals("person", si.getPersons()[0].getName()); + assertEquals("personKey", si.getPersons()[0].getKey()); + assertEquals("personUri", si.getPersons()[0].getUri()); assertEquals(1, si.getExtras().getInt("k")); - assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals("abc", si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); assertEquals("string/r456", si.getIconResName()); @@ -388,9 +398,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("action", si.getIntent().getAction()); assertEquals("val", si.getIntent().getStringExtra("key")); assertEquals(123, si.getRank()); + assertEquals("person", si.getPersons()[0].getName()); + assertEquals("personKey", si.getPersons()[0].getKey()); + assertEquals("personUri", si.getPersons()[0].getUri()); assertEquals(1, si.getExtras().getInt("k")); - assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); @@ -408,9 +421,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); assertEquals(null, si.getIntent()); assertEquals(123, si.getRank()); + assertEquals("person", si.getPersons()[0].getName()); + assertEquals("personKey", si.getPersons()[0].getKey()); + assertEquals("personUri", si.getPersons()[0].getUri()); assertEquals(1, si.getExtras().getInt("k")); - assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); @@ -428,9 +444,11 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(null, si.getCategories()); assertEquals(null, si.getIntent()); assertEquals(0, si.getRank()); + assertEquals(null, si.getPersons()); assertEquals(null, si.getExtras()); - assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags()); + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY + | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); @@ -692,6 +710,12 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") + .setPerson(makePerson("person", "", "")).build()); + assertEquals("text", si.getText()); + assertEquals("person", si.getPersons()[0].getName()); + + si = sorig.clone(/* flags=*/ 0); + si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") .setIntent(makeIntent("action2", ShortcutActivity.class)).build()); assertEquals("text", si.getText()); assertEquals("action2", si.getIntent().getAction()); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index f947baceafd8..56f4a8544f00 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -57,11 +57,6 @@ import org.junit.Test; @Presubmit public class ActivityDisplayTests extends ActivityTestsBase { - @Before - public void setUp() throws Exception { - setupActivityTaskManagerService(); - } - @Test public void testLastFocusedStackIsUpdatedWhenMovingStack() { // Create a stack at bottom. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java index cac9cf69ce4d..ee228610ab21 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java @@ -70,8 +70,6 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase { @Before public void setUpAMLO() throws Exception { - setupActivityTaskManagerService(); - mLaunchObserver = mock(ActivityMetricsLaunchObserver.class); // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger. diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 06360c217b97..8be63fc43adb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -19,8 +19,10 @@ package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; @@ -39,6 +41,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.app.ActivityOptions; +import android.app.servertransaction.ActivityConfigurationChangeItem; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.PauseActivityItem; import android.content.pm.ActivityInfo; @@ -69,7 +72,6 @@ public class ActivityRecordTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build(); mTask = mStack.getChildAt(0); mActivity = mTask.getTopActivity(); @@ -321,4 +323,44 @@ public class ActivityRecordTests extends ActivityTestsBase { assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, mActivity.mRelaunchReason); } + + @Test + public void testSetRequestedOrientationUpdatesConfiguration() throws Exception { + mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); + + mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); + mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), + mActivity.getConfiguration())); + + mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION; + final Configuration newConfig = new Configuration(mActivity.getConfiguration()); + newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT + ? Configuration.ORIENTATION_LANDSCAPE + : Configuration.ORIENTATION_PORTRAIT; + + // Mimic the behavior that display doesn't handle app's requested orientation. + doAnswer(invocation -> { + mTask.onConfigurationChanged(newConfig); + return null; + }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any()); + + final int requestedOrientation; + switch (newConfig.orientation) { + case Configuration.ORIENTATION_LANDSCAPE: + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; + break; + case Configuration.ORIENTATION_PORTRAIT: + requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; + break; + default: + throw new IllegalStateException("Orientation in new config should be either" + + "landscape or portrait."); + } + mActivity.setRequestedOrientation(requestedOrientation); + + final ActivityConfigurationChangeItem expected = + ActivityConfigurationChangeItem.obtain(newConfig); + verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()), + eq(mActivity.appToken), eq(expected)); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index f7b5d26ac87e..59e71c417439 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -64,7 +64,6 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index fda23e9cb73a..35c1edeace2d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -75,7 +75,6 @@ public class ActivityStackTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); mDefaultDisplay = mRootActivityContainer.getDefaultDisplay(); mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */)); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index 2ba2fdbcb959..96db38b14ad5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -56,7 +56,6 @@ public class ActivityStartControllerTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - mService = createActivityTaskManagerService(); mFactory = mock(Factory.class); mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory); mStarter = spy(new ActivityStarter(mController, mService, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 898d107d0c60..a381023590c3 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -117,7 +117,6 @@ public class ActivityStarterTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); mController = mock(ActivityStartController.class); mActivityMetricsLogger = mock(ActivityMetricsLogger.class); clearInvocations(mActivityMetricsLogger); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index d462e69e69c5..68df87e3e27d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -111,6 +111,10 @@ class ActivityTestsBase { @Before public void setUpBase() { mTestInjector.setUp(); + + mService = new TestActivityTaskManagerService(mContext); + mSupervisor = mService.mStackSupervisor; + mRootActivityContainer = mService.mRootActivityContainer; } @After @@ -122,17 +126,6 @@ class ActivityTestsBase { } } - ActivityTaskManagerService createActivityTaskManagerService() { - mService = new TestActivityTaskManagerService(mContext); - mSupervisor = mService.mStackSupervisor; - mRootActivityContainer = mService.mRootActivityContainer; - return mService; - } - - void setupActivityTaskManagerService() { - createActivityTaskManagerService(); - } - /** Creates a {@link TestActivityDisplay}. */ TestActivityDisplay createNewActivityDisplay() { return TestActivityDisplay.create(mSupervisor, sNextDisplayId++); diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index 0c6e632ac9f3..123de2d227bc 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -60,7 +60,7 @@ public class AppTransitionTests extends WindowTestsBase { @BeforeClass public static void setUpRootWindowContainerMock() { - final WindowManagerService wm = WmServiceUtils.getWindowManagerService(); + final WindowManagerService wm = TestSystemServices.getWindowManagerService(); // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal // interaction with surfaceflinger native side. sOriginalRootWindowContainer = wm.mRoot; @@ -74,7 +74,7 @@ public class AppTransitionTests extends WindowTestsBase { @AfterClass public static void tearDownRootWindowContainerMock() { - final WindowManagerService wm = WmServiceUtils.getWindowManagerService(); + final WindowManagerService wm = TestSystemServices.getWindowManagerService(); wm.mRoot = sOriginalRootWindowContainer; sOriginalRootWindowContainer = null; } diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index 8c3dec7f1e75..b28ae40d5056 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -71,7 +71,6 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - mService = createActivityTaskManagerService(); mPersister = new TestLaunchParamsPersister(); mController = new LaunchParamsController(mService, mPersister); } diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 86353643c128..aeda473a9e6e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -102,8 +102,6 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { mFolder = new File(cacheFolder, "launch_params_tests"); deleteRecursively(mFolder); - setupActivityTaskManagerService(); - mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++); final DisplayInfo info = new DisplayInfo(); info.uniqueId = mDisplayUniqueId; diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java index efd7d25c586d..beaac8e58686 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java @@ -52,7 +52,6 @@ public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mService = createActivityTaskManagerService(); mService.mH.runWithScissors(() -> { mHandler = new TestHandler(null, mClock); }, 0); diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index a3f535aa6357..e3bacf96a86c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -82,7 +82,6 @@ public class RootActivityContainerTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index a8b6dc373cbf..dc964806b7a9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -49,7 +49,6 @@ public class RunningTasksTest extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); mRunningTasks = new RunningTasks(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 53e99fae95d4..ace179acdeb5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -75,10 +75,6 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase { @Before public void setUp() throws Exception { - setupActivityTaskManagerService(); - mService.mSupportsFreeformWindowManagement = true; - when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod(); - mActivity = new ActivityBuilder(mService).build(); mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index 99be50be642e..e182c45f009e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -90,7 +90,6 @@ public class TaskRecordTests extends ActivityTestsBase { @Before public void setUp() throws Exception { TaskRecord.setTaskRecordFactory(null); - setupActivityTaskManagerService(); mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java index 05ac8c1072c0..b151fb7a613c 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java @@ -66,7 +66,7 @@ import java.util.concurrent.CountDownLatch; /** * A Test utility class to create a mock {@link WindowManagerService} instance for tests. */ -class WmServiceUtils { +class TestSystemServices { private static StaticMockitoSession sMockitoSession; private static WindowManagerService sService; private static TestWindowManagerPolicy sPolicy; @@ -78,7 +78,7 @@ class WmServiceUtils { .strictness(Strictness.LENIENT) .startMocking(); - runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService); + runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService); } static void tearDownWindowManagerService() { @@ -147,7 +147,7 @@ class WmServiceUtils { final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock(); doReturn(wmLock).when(atms).getGlobalLock(); - sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService); + sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService); sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms); sService.onInitReady(); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 89c1551dffaf..e38118e875e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -101,14 +101,14 @@ class WindowTestsBase { public static void setUpOnceBase() { AttributeCache.init(getInstrumentation().getTargetContext()); - WmServiceUtils.setUpWindowManagerService(); + TestSystemServices.setUpWindowManagerService(); sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); } @AfterClass public static void tearDonwOnceBase() { - WmServiceUtils.tearDownWindowManagerService(); + TestSystemServices.tearDownWindowManagerService(); } @Before @@ -120,7 +120,7 @@ class WindowTestsBase { final Context context = getInstrumentation().getTargetContext(); - mWm = WmServiceUtils.getWindowManagerService(); + mWm = TestSystemServices.getWindowManagerService(); beforeCreateDisplay(); context.getDisplay().getDisplayInfo(mDisplayInfo); @@ -198,7 +198,7 @@ class WindowTestsBase { } // Cleaned up everything in Handler. - WmServiceUtils.cleanupWindowManagerHandlers(); + TestSystemServices.cleanupWindowManagerHandlers(); } catch (Exception e) { Log.e(TAG, "Failed to tear down test", e); throw e; @@ -219,7 +219,7 @@ class WindowTestsBase { * Waits until the main handler for WM has processed all messages. */ void waitUntilHandlersIdle() { - WmServiceUtils.waitUntilWindowManagerHandlersIdle(); + TestSystemServices.waitUntilWindowManagerHandlersIdle(); } private WindowToken createWindowToken( diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.aidl b/telephony/java/android/telephony/CarrierRestrictionRules.aidl new file mode 100644 index 000000000000..8b1f0b918901 --- /dev/null +++ b/telephony/java/android/telephony/CarrierRestrictionRules.aidl @@ -0,0 +1,20 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** @hide */ +package android.telephony; + +parcelable CarrierRestrictionRules; diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java new file mode 100644 index 000000000000..37847aef9167 --- /dev/null +++ b/telephony/java/android/telephony/CarrierRestrictionRules.java @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.service.carrier.CarrierIdentifier; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the list of carrier restrictions. + * Allowed list: it indicates the list of carriers that are allowed. + * Excluded list: it indicates the list of carriers that are excluded. + * Default carrier restriction: it indicates the default behavior and the priority between the two + * lists: + * - not allowed: the device only allows usage of carriers that are present in the allowed list + * and not present in the excluded list. This implies that if a carrier is not present in either + * list, it is not allowed. + * - allowed: the device allows all carriers, except those present in the excluded list and not + * present in the allowed list. This implies that if a carrier is not present in either list, + * it is allowed. + * MultiSim policy: it indicates the behavior in case of devices with two or more SIM cards. + * - MULTISIM_POLICY_NONE: the same configuration is applied to all SIM slots independently. This + * is the default value if none is set. + * - MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT: it indicates that any SIM card can be used + * as far as one SIM card matching the configuration is present in the device. + * + * Both lists support the character '?' as wild character. For example, an entry indicating + * MCC=310 and MNC=??? will match all networks with MCC=310. + * + * Example 1: Allowed list contains MCC and MNC of operator A. Excluded list contains operator B, + * which has same MCC and MNC, but also GID1 value. The priority allowed list is set + * to true. Only SIM cards of operator A are allowed, but not those of B or any other + * operator. + * Example 2: Allowed list contains MCC and MNC of operator A. Excluded list contains an entry + * with same MCC, and '???' as MNC. The priority allowed list is set to false. + * SIM cards of operator A and all SIM cards with a different MCC value are allowed. + * SIM cards of operators with same MCC value and different MNC are not allowed. + * @hide + */ +@SystemApi +public final class CarrierRestrictionRules implements Parcelable { + /** + * The device only allows usage of carriers that are present in the allowed list and not + * present in the excluded list. This implies that if a carrier is not present in either list, + * it is not allowed. + */ + public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0; + + /** + * The device allows all carriers, except those present in the excluded list and not present + * in the allowed list. This implies that if a carrier is not present in either list, it is + * allowed. + */ + public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1; + + /** The same configuration is applied to all SIM slots independently. */ + public static final int MULTISIM_POLICY_NONE = 0; + + /** Any SIM card can be used as far as one SIM card matching the configuration is present. */ + public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "MULTISIM_POLICY_", + value = {MULTISIM_POLICY_NONE, MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT}) + public @interface MultiSimPolicy {} + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CARRIER_RESTRICTION_DEFAULT_", + value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED}) + public @interface CarrierRestrictionDefault {} + + private List<CarrierIdentifier> mAllowedCarriers; + private List<CarrierIdentifier> mExcludedCarriers; + @CarrierRestrictionDefault + private int mCarrierRestrictionDefault; + @MultiSimPolicy + private int mMultiSimPolicy; + + private CarrierRestrictionRules() { + mAllowedCarriers = new ArrayList<CarrierIdentifier>(); + mExcludedCarriers = new ArrayList<CarrierIdentifier>(); + mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED; + mMultiSimPolicy = MULTISIM_POLICY_NONE; + } + + private CarrierRestrictionRules(Parcel in) { + mAllowedCarriers = new ArrayList<CarrierIdentifier>(); + mExcludedCarriers = new ArrayList<CarrierIdentifier>(); + + in.readTypedList(mAllowedCarriers, CarrierIdentifier.CREATOR); + in.readTypedList(mExcludedCarriers, CarrierIdentifier.CREATOR); + mCarrierRestrictionDefault = in.readInt(); + mMultiSimPolicy = in.readInt(); + } + + /** + * Creates a new builder for this class + * @hide + */ + public static Builder newBuilder() { + return new Builder(); + } + + /** + * Indicates if all carriers are allowed + */ + public boolean isAllCarriersAllowed() { + return (mAllowedCarriers.isEmpty() && mExcludedCarriers.isEmpty() + && mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_ALLOWED); + } + + /** + * Retrieves list of allowed carriers + * + * @return the list of allowed carriers + */ + public @NonNull List<CarrierIdentifier> getAllowedCarriers() { + return mAllowedCarriers; + } + + /** + * Retrieves list of excluded carriers + * + * @return the list of excluded carriers + */ + public @NonNull List<CarrierIdentifier> getExcludedCarriers() { + return mExcludedCarriers; + } + + /** + * Retrieves the default behavior of carrier restrictions + */ + public @CarrierRestrictionDefault int getDefaultCarrierRestriction() { + return mCarrierRestrictionDefault; + } + + /** + * @return The policy used for multi-SIM devices + */ + public @MultiSimPolicy int getMultiSimPolicy() { + return mMultiSimPolicy; + } + + /** + * {@link Parcelable#writeToParcel} + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeTypedList(mAllowedCarriers); + out.writeTypedList(mExcludedCarriers); + out.writeInt(mCarrierRestrictionDefault); + out.writeInt(mMultiSimPolicy); + } + + /** + * {@link Parcelable#describeContents} + */ + @Override + public int describeContents() { + return 0; + } + + /** + * {@link Parcelable.Creator} + */ + public static final Creator<CarrierRestrictionRules> CREATOR = + new Creator<CarrierRestrictionRules>() { + @Override + public CarrierRestrictionRules createFromParcel(Parcel in) { + return new CarrierRestrictionRules(in); + } + + @Override + public CarrierRestrictionRules[] newArray(int size) { + return new CarrierRestrictionRules[size]; + } + }; + + @Override + public String toString() { + return "CarrierRestrictionRules(allowed:" + mAllowedCarriers + ", excluded:" + + mExcludedCarriers + ", default:" + mCarrierRestrictionDefault + + ", multisim policy:" + mMultiSimPolicy + ")"; + } + + /** + * Builder for a {@link CarrierRestrictionRules}. + */ + public static class Builder { + private final CarrierRestrictionRules mRules; + + /** {@hide} */ + public Builder() { + mRules = new CarrierRestrictionRules(); + } + + /** build command */ + public CarrierRestrictionRules build() { + return mRules; + } + + /** + * Indicate that all carriers are allowed. + */ + public Builder setAllCarriersAllowed() { + mRules.mAllowedCarriers.clear(); + mRules.mExcludedCarriers.clear(); + mRules.mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_ALLOWED; + return this; + } + + /** + * Set list of allowed carriers. + * + * @param allowedCarriers list of allowed carriers + */ + public Builder setAllowedCarriers(List<CarrierIdentifier> allowedCarriers) { + mRules.mAllowedCarriers = new ArrayList<CarrierIdentifier>(allowedCarriers); + return this; + } + + /** + * Set list of excluded carriers. + * + * @param excludedCarriers list of excluded carriers + */ + public Builder setExcludedCarriers(List<CarrierIdentifier> excludedCarriers) { + mRules.mExcludedCarriers = new ArrayList<CarrierIdentifier>(excludedCarriers); + return this; + } + + /** + * Set the default behavior of the carrier restrictions + * + * @param carrierRestrictionDefault prioritized carrier list + */ + public Builder setDefaultCarrierRestriction( + @CarrierRestrictionDefault int carrierRestrictionDefault) { + mRules.mCarrierRestrictionDefault = carrierRestrictionDefault; + return this; + } + + /** + * Set the policy to be used for multi-SIM devices + * + * @param multiSimPolicy multi SIM policy + */ + public Builder setMultiSimPolicy(@MultiSimPolicy int multiSimPolicy) { + mRules.mMultiSimPolicy = multiSimPolicy; + return this; + } + } +} diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index c81670139eae..9fee5932dadc 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -805,9 +805,11 @@ public class PhoneStateListener { PhoneStateListener psl = mPhoneStateListenerWeakRef.get(); if (psl == null) return; - Binder.withCleanCallingIdentity( - () -> mExecutor.execute( - () -> psl.onDataConnectionStateChanged(state, networkType))); + Binder.withCleanCallingIdentity(() -> mExecutor.execute( + () -> { + psl.onDataConnectionStateChanged(state, networkType); + psl.onDataConnectionStateChanged(state); + })); } public void onDataActivity(int direction) { diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 3311218bdb3c..75b117792844 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -9055,6 +9055,8 @@ public class TelephonyManager { * <p>This method works only on devices with {@link * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled. * + * @deprecated use setCarrierRestrictionRules instead + * * @return The number of carriers set successfully. Should be length of * carrierList on success; -1 if carrierList null or on error. * @hide @@ -9062,44 +9064,144 @@ public class TelephonyManager { @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) { + // Execute the method setCarrierRestrictionRules with an empty excluded list and + // indicating priority for the allowed list. + CarrierRestrictionRules carrierRestrictionRules = CarrierRestrictionRules.newBuilder() + .setAllowedCarriers(carriers) + .setDefaultCarrierRestriction( + CarrierRestrictionRules.CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) + .build(); + + int result = setCarrierRestrictionRules(carrierRestrictionRules); + + // Convert boolean result into int, as required by this method. + if (result == SET_CARRIER_RESTRICTION_SUCCESS) { + return carriers.size(); + } else { + return -1; + } + } + + /** + * The carrier restrictions were successfully set. + * @hide + */ + @SystemApi + public static final int SET_CARRIER_RESTRICTION_SUCCESS = 0; + + /** + * The carrier restrictions were not set due to lack of support in the modem. This can happen + * if the modem does not support setting the carrier restrictions or if the configuration + * passed in the {@code setCarrierRestrictionRules} is not supported by the modem. + * @hide + */ + @SystemApi + public static final int SET_CARRIER_RESTRICTION_NOT_SUPPORTED = 1; + + /** + * The setting of carrier restrictions failed. + * @hide + */ + @SystemApi + public static final int SET_CARRIER_RESTRICTION_ERROR = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"SET_CARRIER_RESTRICTION_"}, + value = { + SET_CARRIER_RESTRICTION_SUCCESS, + SET_CARRIER_RESTRICTION_NOT_SUPPORTED, + SET_CARRIER_RESTRICTION_ERROR + }) + public @interface SetCarrierRestrictionResult {} + + /** + * Set the allowed carrier list and the excluded carrier list indicating the priority between + * the two lists. + * Requires system privileges. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE} + * + * <p>This method works only on devices with {@link + * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled. + * + * @return {@link #SET_CARRIER_RESTRICTION_SUCCESS} in case of success. + * {@link #SET_CARRIER_RESTRICTION_NOT_SUPPORTED} if the modem does not support the + * configuration. {@link #SET_CARRIER_RESTRICTION_ERROR} in all other error cases. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @SetCarrierRestrictionResult + public int setCarrierRestrictionRules(@NonNull CarrierRestrictionRules rules) { try { ITelephony service = getITelephony(); if (service != null) { - return service.setAllowedCarriers(slotIndex, carriers); + return service.setAllowedCarriers(rules); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e); } catch (NullPointerException e) { Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e); } - return -1; + return SET_CARRIER_RESTRICTION_ERROR; } /** * Get the allowed carrier list for slotIndex. - * Require system privileges. In the future we may add this to carrier APIs. + * Requires system privileges. * * <p>This method returns valid data on devices with {@link * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled. * + * @deprecated Apps should use {@link getCarriersRestrictionRules} to retrieve the list of + * allowed and excliuded carriers, as the result of this API is valid only when the excluded + * list is empty. This API could return an empty list, even if some restrictions are present. + * * @return List of {@link android.telephony.CarrierIdentifier}; empty list * means all carriers are allowed. * @hide */ + @Deprecated @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public List<CarrierIdentifier> getAllowedCarriers(int slotIndex) { + CarrierRestrictionRules carrierRestrictionRule = getCarrierRestrictionRules(); + if (carrierRestrictionRule != null) { + return carrierRestrictionRule.getAllowedCarriers(); + } + return new ArrayList<CarrierIdentifier>(0); + } + + /** + * Get the allowed carrier list and the excluded carrier list indicating the priority between + * the two lists. + * Require system privileges. In the future we may add this to carrier APIs. + * + * <p>This method returns valid data on devices with {@link + * android.content.pm.PackageManager#FEATURE_TELEPHONY_CARRIERLOCK} enabled. + * + * @return {@link CarrierRestrictionRules} which contains the allowed carrier list and the + * excluded carrier list with the priority between the two lists. Returns {@code null} + * in case of error. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @Nullable + public CarrierRestrictionRules getCarrierRestrictionRules() { try { ITelephony service = getITelephony(); if (service != null) { - return service.getAllowedCarriers(slotIndex); + return service.getAllowedCarriers(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e); } catch (NullPointerException e) { Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e); } - return new ArrayList<CarrierIdentifier>(0); + return null; } /** diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java index a5f56bbebd75..e68256d086bc 100644 --- a/telephony/java/android/telephony/emergency/EmergencyNumber.java +++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java @@ -27,6 +27,7 @@ import android.telephony.Rlog; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -176,6 +177,12 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu * Bit-field which indicates the number is from the platform-maintained database. */ public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 1 << 4; + /** + * Bit-field which indicates the number is from test mode. + * + * @hide + */ + public static final int EMERGENCY_NUMBER_SOURCE_TEST = 1 << 5; /** Bit-field which indicates the number is from the modem config. */ public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG = EmergencyNumberSource.MODEM_CONFIG; @@ -327,6 +334,21 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu } /** + * Returns the bitmask of emergency service categories of the emergency number for + * internal dialing. + * + * @return bitmask of the emergency service categories + * + * @hide + */ + public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmaskInternalDial() { + if (mEmergencyNumberSourceBitmask == EMERGENCY_NUMBER_SOURCE_DATABASE) { + return EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED; + } + return mEmergencyServiceCategoryBitmask; + } + + /** * Returns the emergency service categories of the emergency number. * * Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only @@ -577,6 +599,7 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu emergencyNumberList.remove(i--); } } + Collections.sort(emergencyNumberList); } /** @@ -613,6 +636,12 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) { return false; } + // Never merge two numbers if one of them is from test mode but the other one is not; + // This supports to remove a number from the test mode. + if (first.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST) + ^ second.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)) { + return false; + } return true; } @@ -638,4 +667,13 @@ public final class EmergencyNumber implements Parcelable, Comparable<EmergencyNu } return null; } + + /** + * Validate Emergency Number address that only allows '0'-'9', '*', or '#' + * + * @hide + */ + public static boolean validateEmergencyNumberAddress(String address) { + return address.matches("[0-9*#]+"); + } } diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 525a96a4dae9..59167b7d5bba 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -347,6 +347,9 @@ public final class ImsCallProfile implements Parcelable { private @EmergencyCallRouting int mEmergencyCallRouting = EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN; + /** Indicates if the call is for testing purpose */ + private boolean mEmergencyCallTesting = false; + /** * Extras associated with this {@link ImsCallProfile}. * <p> @@ -534,9 +537,10 @@ public final class ImsCallProfile implements Parcelable { + ", callType=" + mCallType + ", restrictCause=" + mRestrictCause + ", mediaProfile=" + mMediaProfile.toString() - + ", emergencyServiceCategories=" + mEmergencyCallRouting + + ", emergencyServiceCategories=" + mEmergencyServiceCategories + ", emergencyUrns=" + mEmergencyUrns - + ", emergencyCallRouting=" + mEmergencyCallRouting + " }"; + + ", emergencyCallRouting=" + mEmergencyCallRouting + + ", emergencyCallTesting=" + mEmergencyCallTesting + " }"; } @Override @@ -554,6 +558,7 @@ public final class ImsCallProfile implements Parcelable { out.writeInt(mEmergencyServiceCategories); out.writeStringList(mEmergencyUrns); out.writeInt(mEmergencyCallRouting); + out.writeBoolean(mEmergencyCallTesting); } private void readFromParcel(Parcel in) { @@ -564,6 +569,7 @@ public final class ImsCallProfile implements Parcelable { mEmergencyServiceCategories = in.readInt(); mEmergencyUrns = in.createStringArrayList(); mEmergencyCallRouting = in.readInt(); + mEmergencyCallTesting = in.readBoolean(); } public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() { @@ -784,9 +790,11 @@ public final class ImsCallProfile implements Parcelable { * @hide */ public void setEmergencyCallInfo(EmergencyNumber num) { - setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask()); + setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmaskInternalDial()); setEmergencyUrns(num.getEmergencyUrns()); setEmergencyCallRouting(num.getEmergencyCallRouting()); + setEmergencyCallTesting(num.getEmergencyNumberSourceBitmask() + == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST); } /** @@ -843,6 +851,15 @@ public final class ImsCallProfile implements Parcelable { } /** + * Set if this is for testing emergency call, only valid if {@link #getServiceType} returns + * {@link #SERVICE_TYPE_EMERGENCY}. + */ + @VisibleForTesting + public void setEmergencyCallTesting(boolean isTesting) { + mEmergencyCallTesting = isTesting; + } + + /** * Get the emergency service categories, only valid if {@link #getServiceType} returns * {@link #SERVICE_TYPE_EMERGENCY} * @@ -892,4 +909,11 @@ public final class ImsCallProfile implements Parcelable { public @EmergencyCallRouting int getEmergencyCallRouting() { return mEmergencyCallRouting; } + + /** + * Get if the emergency call is for testing purpose. + */ + public boolean isEmergencyCallTesting() { + return mEmergencyCallTesting; + } } diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index e2350fe78500..9414abd98b1c 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -92,7 +92,7 @@ public class ImsMmTelManager { public static final int WIFI_MODE_WIFI_PREFERRED = 2; /** - * Callback class for receiving Registration callback events. + * Callback class for receiving IMS network Registration callback events. * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback) * @see #unregisterImsRegistrationCallback(RegistrationCallback) */ @@ -241,7 +241,8 @@ public class ImsMmTelManager { } /** - * Receives IMS capability status updates from the ImsService. + * Receives IMS capability status updates from the ImsService. This information is also + * available via the {@link #isAvailable(int, int)} method below. * * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback) * @see #unregisterMmTelCapabilityCallback(CapabilityCallback) @@ -290,6 +291,8 @@ public class ImsMmTelManager { * If unavailable, the feature is not able to support the unavailable capability at this * time. * + * This information can also be queried using the {@link #isAvailable(int, int)} API. + * * @param capabilities The new availability of the capabilities. */ public void onCapabilitiesStatusChanged( @@ -304,7 +307,7 @@ public class ImsMmTelManager { /**@hide*/ // Only exposed as public method for compatibility with deprecated ImsManager APIs. // TODO: clean up dependencies and change back to private visibility. - public void setExecutor(Executor executor) { + public final void setExecutor(Executor executor) { mBinder.setExecutor(executor); } } @@ -342,8 +345,7 @@ public class ImsMmTelManager { * Registers a {@link RegistrationCallback} with the system, which will provide registration * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed - * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up - * after a subscription is removed. + * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up. * * When the callback is registered, it will initiate the callback c to be called with the * current registration state. @@ -351,6 +353,12 @@ public class ImsMmTelManager { * @param executor The executor the callback events should be run on. * @param c The {@link RegistrationCallback} to be added. * @see #unregisterImsRegistrationCallback(RegistrationCallback) + * @throws IllegalArgumentException if the subscription associated with this callback is not + * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or + * {@link CapabilityCallback} callback. + * @throws IllegalStateException if the subscription associated with this callback is valid, but + * the {@link ImsService} associated with the subscription is not available. This can happen if + * the service crashed, for example. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@CallbackExecutor Executor executor, @@ -370,11 +378,17 @@ public class ImsMmTelManager { } /** - * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning - * up to avoid memory leaks or when the subscription is removed. + * Removes an existing {@link RegistrationCallback}. + * + * When the subscription associated with this callback is removed (SIM removed, ESIM swap, + * etc...), this callback will automatically be removed. If this method is called for an + * inactive subscription, it will result in a no-op. + * * @param c The {@link RegistrationCallback} to be removed. * @see SubscriptionManager.OnSubscriptionsChangedListener * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) + * @throws IllegalArgumentException if the subscription ID associated with this callback is + * invalid. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) { @@ -389,12 +403,14 @@ public class ImsMmTelManager { } /** - * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability - * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. + * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service + * availability updates for the subscription specified in + * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)} + * can also be used to query this information at any time. + * * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to * subscription changed events and call - * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a - * subscription is removed. + * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up. * * When the callback is registered, it will initiate the callback c to be called with the * current capabilities. @@ -402,9 +418,15 @@ public class ImsMmTelManager { * @param executor The executor the callback events should be run on. * @param c The MmTel {@link CapabilityCallback} to be registered. * @see #unregisterMmTelCapabilityCallback(CapabilityCallback) + * @throws IllegalArgumentException if the subscription associated with this callback is not + * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or + * {@link CapabilityCallback} callback. + * @throws IllegalStateException if the subscription associated with this callback is valid, but + * the {@link ImsService} associated with the subscription is not available. This can happen if + * the service crashed, for example. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor, + public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor, @NonNull CapabilityCallback c) { if (c == null) { throw new IllegalArgumentException("Must include a non-null RegistrationCallback."); @@ -421,10 +443,15 @@ public class ImsMmTelManager { } /** - * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning - * up to avoid memory leaks. + * Removes an existing MmTel {@link CapabilityCallback}. + * + * When the subscription associated with this callback is removed (SIM removed, ESIM swap, + * etc...), this callback will automatically be removed. If this method is called for an + * inactive subscription, it will result in a no-op. * @param c The MmTel {@link CapabilityCallback} to be removed. * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) + * @throws IllegalArgumentException if the subscription ID associated with this callback is + * invalid. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) { diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 916e282f642e..d37198a3e25d 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -133,33 +133,40 @@ public class ProvisioningManager { } /** - * Register a new {@link Callback} to listen to changes to changes in - * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to - * Subscription changed events and call - * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a - * subscription is removed. + * Register a new {@link Callback} to listen to changes to changes in IMS provisioning. + * + * When the subscription associated with this callback is removed (SIM removed, ESIM swap, + * etc...), this callback will automatically be removed. * @param executor The {@link Executor} to call the callback methods on * @param callback The provisioning callbackto be registered. * @see #unregisterProvisioningChangedCallback(Callback) * @see SubscriptionManager.OnSubscriptionsChangedListener + * @throws IllegalArgumentException if the subscription associated with this callback is not + * active (SIM is not inserted, ESIM inactive) or the subscription is invalid. + * @throws IllegalStateException if the subscription associated with this callback is valid, but + * the {@link ImsService} associated with the subscription is not available. This can happen if + * the service crashed, for example. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor, @NonNull Callback callback) { callback.setExecutor(executor); try { - getITelephony().registerImsProvisioningChangedCallback(mSubId, - callback.getBinder()); + getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder()); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } /** - * Unregister an existing {@link Callback}. Ensure to call this method when cleaning - * up to avoid memory leaks or when the subscription is removed. + * Unregister an existing {@link Callback}. When the subscription associated with this + * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be + * removed. If this method is called for an inactive subscription, it will result in a no-op. * @param callback The existing {@link Callback} to be removed. * @see #registerProvisioningChangedCallback(Executor, Callback) + * + * @throws IllegalArgumentException if the subscription associated with this callback is + * invalid. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull Callback callback) { diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index c5d82c5949f0..62b9d363e35e 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -28,6 +28,7 @@ import android.net.Uri; import android.service.carrier.CarrierIdentifier; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; +import android.telephony.CarrierRestrictionRules; import android.telephony.CellInfo; import android.telephony.ClientRequestStats; import android.telephony.IccOpenLogicalChannelResponse; @@ -41,6 +42,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyHistogram; import android.telephony.VisualVoicemailSmsFilterSettings; +import android.telephony.emergency.EmergencyNumber; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; @@ -1292,22 +1294,27 @@ interface ITelephony { List<TelephonyHistogram> getTelephonyHistograms(); /** - * Set the allowed carrier list for slotIndex - * Require system privileges. In the future we may add this to carrier APIs. + * Set the allowed carrier list and the excluded carrier list, indicating the priority between + * the two lists. * - * @return The number of carriers set successfully. Should match length of - * carriers on success. + * <p>Requires system privileges. In the future we may add this to carrier APIs. + * + * @return {@link #SET_CARRIER_RESTRICTION_SUCCESS} in case of success. + * {@link #SET_CARRIER_RESTRICTION_NOT_SUPPORTED} if the modem does not support the + * configuration. {@link #SET_CARRIER_RESTRICTION_ERROR} in all other error cases. */ - int setAllowedCarriers(int slotIndex, in List<CarrierIdentifier> carriers); + int setAllowedCarriers(in CarrierRestrictionRules carrierRestrictionRules); /** - * Get the allowed carrier list for slotIndex. - * Require system privileges. In the future we may add this to carrier APIs. + * Get the allowed carrier list and the excluded carrier list indicating the priority between + * the two lists. + * + * <p>Requires system privileges. In the future we may add this to carrier APIs. * - * @return List of {@link android.service.carrier.CarrierIdentifier}; empty list - * means all carriers are allowed. + * @return {@link CarrierRestrictionRules}; empty lists mean all carriers are allowed. It + * returns null in case of error. */ - List<CarrierIdentifier> getAllowedCarriers(int slotIndex); + CarrierRestrictionRules getAllowedCarriers(); /** * Returns carrier id of the given subscription. @@ -1776,4 +1783,14 @@ interface ITelephony { * Set the String provisioning value for the provisioning key specified. */ int setImsProvisioningString(int subId, int key, String value); + + /** + * Update Emergency Number List for Test Mode. + */ + void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num); + + /** + * Get the full emergency number list for Test Mode. + */ + List<String> getEmergencyNumberListTestMode(); } diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml index 0be1ea0fdfd2..17eb029166f0 100644 --- a/tests/ActivityViewTest/AndroidManifest.xml +++ b/tests/ActivityViewTest/AndroidManifest.xml @@ -57,5 +57,10 @@ android:exported="true" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"> </activity> + + <activity android:name=".ActivityViewVisibilityActivity" + android:label="AV Visibility" + android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density"> + </activity> </application> </manifest> diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml index ba2e91166440..efcaef679a9c 100644 --- a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml +++ b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml @@ -41,4 +41,10 @@ android:text="Test Resize ActivityView" android:textAllCaps="false"/> + <Button + android:id="@+id/visibility_activity_view_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Test ActivityView Visibility" + android:textAllCaps="false"/> </LinearLayout> diff --git a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml new file mode 100644 index 000000000000..d29d4dfc0428 --- /dev/null +++ b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="#cfd8dc"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <Button + android:id="@+id/activity_launch_button" + android:layout_width="200dp" + android:layout_height="wrap_content" + android:text="Launch test activity" /> + + <Spinner + android:id="@+id/visibility_spinner" + android:layout_width="200dp" + android:layout_height="match_parent"/> + + </LinearLayout> + + <ActivityView + android:id="@+id/activity_view" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + +</LinearLayout> diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java index 66f0c6a56afd..4f09c28fe711 100644 --- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java +++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java @@ -35,5 +35,8 @@ public class ActivityViewMainActivity extends Activity { findViewById(R.id.resize_activity_view_button).setOnClickListener( v -> startActivity(new Intent(this, ActivityViewResizeActivity.class))); + + findViewById(R.id.visibility_activity_view_button).setOnClickListener( + v -> startActivity(new Intent(this, ActivityViewVisibilityActivity.class))); } } diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java index ba2c764bd7d7..52aba2b13c42 100644 --- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java +++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java @@ -24,12 +24,14 @@ import static android.view.MotionEvent.ACTION_UP; import android.app.Activity; import android.content.res.Configuration; import android.os.Bundle; +import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewTreeObserver; import android.widget.TextView; public class ActivityViewTestActivity extends Activity { + private static final String TAG = "ActivityViewTestActivity"; private View mRoot; private TextView mTextView; @@ -84,6 +86,7 @@ public class ActivityViewTestActivity extends Activity { } private void updateStateText(String state) { + Log.d(TAG, state); mTextView.setText(state); } diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java new file mode 100644 index 000000000000..ecd2cf3c578e --- /dev/null +++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.android.test.activityview; + +import static android.view.View.GONE; +import static android.view.View.INVISIBLE; +import static android.view.View.VISIBLE; + +import android.app.Activity; +import android.app.ActivityView; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.Spinner; + +public class ActivityViewVisibilityActivity extends Activity { + private static final String[] sVisibilityOptions = {"VISIBLE", "INVISIBLE", "GONE"}; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_view_visibility_activity); + + final ActivityView activityView = findViewById(R.id.activity_view); + final Button launchButton = findViewById(R.id.activity_launch_button); + launchButton.setOnClickListener(v -> { + final Intent intent = new Intent(this, ActivityViewTestActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); + activityView.startActivity(intent); + }); + + final Spinner visibilitySpinner = findViewById(R.id.visibility_spinner); + final ArrayAdapter<String> adapter = new ArrayAdapter<>(this, + android.R.layout.simple_spinner_item, sVisibilityOptions); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + visibilitySpinner.setAdapter(adapter); + visibilitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + switch (position) { + case 0: + activityView.setVisibility(VISIBLE); + break; + case 1: + activityView.setVisibility(INVISIBLE); + break; + case 2: + activityView.setVisibility(GONE); + break; + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + } + }); + } +} diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 77cd9d8f20a3..c2e735e184b0 100644 --- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -178,10 +178,10 @@ public class RollbackTest { } /** - * Test that rollback data is properly persisted. + * Test that multiple available rollbacks are properly persisted. */ @Test - public void testRollbackDataPersistence() throws Exception { + public void testAvailableRollbackPersistence() throws Exception { try { RollbackTestUtils.adoptShellPermissionIdentity( Manifest.permission.INSTALL_PACKAGES, @@ -190,36 +190,157 @@ public class RollbackTest { RollbackManager rm = RollbackTestUtils.getRollbackManager(); - // TODO: Test this with multi-package rollback, not just single - // package rollback. - // Prep installation of TEST_APP_A RollbackTestUtils.uninstall(TEST_APP_A); RollbackTestUtils.install("RollbackTestAppAv1.apk", false); RollbackTestUtils.install("RollbackTestAppAv2.apk", true); assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + RollbackTestUtils.uninstall(TEST_APP_B); + RollbackTestUtils.install("RollbackTestAppBv1.apk", false); + RollbackTestUtils.install("RollbackTestAppBv2.apk", true); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + + // Both test apps should now be available for rollback. + // TODO: See if there is a way to remove this race condition + // between when the app is installed and when the rollback + // is made available. + Thread.sleep(1000); + + assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A)); + RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A); + assertNotNull(rollbackA); + assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName); + assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode); + + assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B)); + RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B); + assertNotNull(rollbackB); + assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName); + assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode); + + // Reload the persisted data. + rm.reloadPersistedData(); + + // The apps should still be available for rollback. + rollbackA = rm.getAvailableRollback(TEST_APP_A); + assertNotNull(rollbackA); + assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName); + assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode); + + assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B)); + rollbackB = rm.getAvailableRollback(TEST_APP_B); + assertNotNull(rollbackB); + assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName); + assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode); + + // Rollback of B should not rollback A + RollbackTestUtils.rollback(rollbackB); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + } finally { + RollbackTestUtils.dropShellPermissionIdentity(); + } + } + + /** + * Test that available multi-package rollbacks are properly persisted. + */ + @Test + public void testAvailableMultiPackageRollbackPersistence() throws Exception { + try { + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.MANAGE_ROLLBACKS); + + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + + RollbackTestUtils.uninstall(TEST_APP_A); + RollbackTestUtils.uninstall(TEST_APP_B); + RollbackTestUtils.installMultiPackage(false, + "RollbackTestAppAv1.apk", + "RollbackTestAppBv1.apk"); + RollbackTestUtils.installMultiPackage(true, + "RollbackTestAppAv2.apk", + "RollbackTestAppBv2.apk"); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + // The app should now be available for rollback. // TODO: See if there is a way to remove this race condition // between when the app is installed and when the rollback // is made available. Thread.sleep(1000); + assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A)); - RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A); - assertNotNull(rollback); - assertEquals(TEST_APP_A, rollback.targetPackage.packageName); - assertEquals(2, rollback.targetPackage.higherVersion.versionCode); - assertEquals(1, rollback.targetPackage.lowerVersion.versionCode); + RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A); + assertNotNull(rollbackA); + assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName); + assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode); + + assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B)); + RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B); + assertNotNull(rollbackB); + assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName); + assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode); // Reload the persisted data. rm.reloadPersistedData(); - // The app should still be available for rollback. + // The apps should still be available for rollback. + rollbackA = rm.getAvailableRollback(TEST_APP_A); + assertNotNull(rollbackA); + assertEquals(TEST_APP_A, rollbackA.targetPackage.packageName); + assertEquals(2, rollbackA.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackA.targetPackage.lowerVersion.versionCode); + + assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B)); + rollbackB = rm.getAvailableRollback(TEST_APP_B); + assertNotNull(rollbackB); + assertEquals(TEST_APP_B, rollbackB.targetPackage.packageName); + assertEquals(2, rollbackB.targetPackage.higherVersion.versionCode); + assertEquals(1, rollbackB.targetPackage.lowerVersion.versionCode); + + // Rollback of B should rollback A as well + RollbackTestUtils.rollback(rollbackB); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B)); + } finally { + RollbackTestUtils.dropShellPermissionIdentity(); + } + } + + /** + * Test that recently executed rollback data is properly persisted. + */ + @Test + public void testRecentlyExecutedRollbackPersistence() throws Exception { + try { + RollbackTestUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.MANAGE_ROLLBACKS); + + RollbackManager rm = RollbackTestUtils.getRollbackManager(); + + RollbackTestUtils.uninstall(TEST_APP_A); + RollbackTestUtils.install("RollbackTestAppAv1.apk", false); + RollbackTestUtils.install("RollbackTestAppAv2.apk", true); + assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A)); + + // The app should now be available for rollback. + // TODO: See if there is a way to remove this race condition + // between when the app is installed and when the rollback + // is made available. + Thread.sleep(1000); assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A)); - rollback = rm.getAvailableRollback(TEST_APP_A); - assertNotNull(rollback); - assertEquals(TEST_APP_A, rollback.targetPackage.packageName); - assertEquals(2, rollback.targetPackage.higherVersion.versionCode); - assertEquals(1, rollback.targetPackage.lowerVersion.versionCode); + RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A); // Roll back the app. RollbackTestUtils.rollback(rollback); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 2a92a7dabd98..882babff4aee 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -122,7 +122,6 @@ import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkUtils; import android.net.RouteInfo; -import android.net.StringNetworkSpecifier; import android.net.UidRange; import android.net.metrics.IpConnectivityLog; import android.net.shared.NetworkMonitorUtils; @@ -145,6 +144,7 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.test.mock.MockContentResolver; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -2567,16 +2567,76 @@ public class ConnectivityServiceTest { return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI); } + /** + * Verify request matching behavior with network specifiers. + * + * Note: this test is somewhat problematic since it involves removing capabilities from + * agents - i.e. agents rejecting requests which they previously accepted. This is flagged + * as a WTF bug in + * {@link ConnectivityService#mixInCapabilities(NetworkAgentInfo, NetworkCapabilities)} but + * does work. + */ @Test public void testNetworkSpecifier() { + // A NetworkSpecifier subclass that matches all networks but must not be visible to apps. + class ConfidentialMatchAllNetworkSpecifier extends NetworkSpecifier implements + Parcelable { + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + return true; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) {} + + @Override + public NetworkSpecifier redact() { + return null; + } + } + + // A network specifier that matches either another LocalNetworkSpecifier with the same + // string or a ConfidentialMatchAllNetworkSpecifier, and can be passed to apps as is. + class LocalStringNetworkSpecifier extends NetworkSpecifier implements Parcelable { + private String mString; + + LocalStringNetworkSpecifier(String string) { + mString = string; + } + + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + if (other instanceof LocalStringNetworkSpecifier) { + return TextUtils.equals(mString, + ((LocalStringNetworkSpecifier) other).mString); + } + if (other instanceof ConfidentialMatchAllNetworkSpecifier) return true; + return false; + } + + @Override + public int describeContents() { + return 0; + } + @Override + public void writeToParcel(Parcel dest, int flags) {} + } + + NetworkRequest rEmpty1 = newWifiRequestBuilder().build(); NetworkRequest rEmpty2 = newWifiRequestBuilder().setNetworkSpecifier((String) null).build(); NetworkRequest rEmpty3 = newWifiRequestBuilder().setNetworkSpecifier("").build(); NetworkRequest rEmpty4 = newWifiRequestBuilder().setNetworkSpecifier( (NetworkSpecifier) null).build(); - NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier("foo").build(); + NetworkRequest rFoo = newWifiRequestBuilder().setNetworkSpecifier( + new LocalStringNetworkSpecifier("foo")).build(); NetworkRequest rBar = newWifiRequestBuilder().setNetworkSpecifier( - new StringNetworkSpecifier("bar")).build(); + new LocalStringNetworkSpecifier("bar")).build(); TestNetworkCallback cEmpty1 = new TestNetworkCallback(); TestNetworkCallback cEmpty2 = new TestNetworkCallback(); @@ -2585,7 +2645,7 @@ public class ConnectivityServiceTest { TestNetworkCallback cFoo = new TestNetworkCallback(); TestNetworkCallback cBar = new TestNetworkCallback(); TestNetworkCallback[] emptyCallbacks = new TestNetworkCallback[] { - cEmpty1, cEmpty2, cEmpty3 }; + cEmpty1, cEmpty2, cEmpty3, cEmpty4 }; mCm.registerNetworkCallback(rEmpty1, cEmpty1); mCm.registerNetworkCallback(rEmpty2, cEmpty2); @@ -2594,6 +2654,9 @@ public class ConnectivityServiceTest { mCm.registerNetworkCallback(rFoo, cFoo); mCm.registerNetworkCallback(rBar, cBar); + LocalStringNetworkSpecifier nsFoo = new LocalStringNetworkSpecifier("foo"); + LocalStringNetworkSpecifier nsBar = new LocalStringNetworkSpecifier("bar"); + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(false); cEmpty1.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); @@ -2602,30 +2665,54 @@ public class ConnectivityServiceTest { cEmpty4.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertNoCallbacks(cFoo, cBar); - mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("foo")); + mWiFiNetworkAgent.setNetworkSpecifier(nsFoo); cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); for (TestNetworkCallback c: emptyCallbacks) { - c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo), + mWiFiNetworkAgent); } - cFoo.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo), + mWiFiNetworkAgent); + assertEquals(nsFoo, + mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier()); cFoo.assertNoCallback(); - mWiFiNetworkAgent.setNetworkSpecifier(new StringNetworkSpecifier("bar")); + mWiFiNetworkAgent.setNetworkSpecifier(nsBar); cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); for (TestNetworkCallback c: emptyCallbacks) { - c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar), + mWiFiNetworkAgent); } - cBar.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); + cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar), + mWiFiNetworkAgent); + assertEquals(nsBar, + mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier()); + cBar.assertNoCallback(); + + mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier()); + cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + for (TestNetworkCallback c : emptyCallbacks) { + c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null, + mWiFiNetworkAgent); + } + cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null, + mWiFiNetworkAgent); + cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null, + mWiFiNetworkAgent); + assertNull( + mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier()); + cFoo.assertNoCallback(); cBar.assertNoCallback(); mWiFiNetworkAgent.setNetworkSpecifier(null); + cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent); for (TestNetworkCallback c: emptyCallbacks) { c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent); } - assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cFoo, cBar); + assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar); } @Test diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 58702dc465cc..e0d2f48e8dcf 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -1164,8 +1164,6 @@ bool ResourceParser::ParseOverlayable(xml::XmlPullParser* parser, ParsedResource current_policies |= OverlayableItem::Policy::kPublic; } else if (trimmed_part == "product") { current_policies |= OverlayableItem::Policy::kProduct; - } else if (trimmed_part == "product_services") { - current_policies |= OverlayableItem::Policy::kProductServices; } else if (trimmed_part == "system") { current_policies |= OverlayableItem::Policy::kSystem; } else if (trimmed_part == "vendor") { diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index debca9c1e1ba..827c7deaf452 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -935,9 +935,6 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { <policy type="product"> <item type="string" name="bar" /> </policy> - <policy type="product_services"> - <item type="string" name="baz" /> - </policy> <policy type="system"> <item type="string" name="fiz" /> </policy> @@ -966,14 +963,6 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct)); - search_result = table_.FindResource(test::ParseNameOrDie("string/baz")); - ASSERT_TRUE(search_result); - ASSERT_THAT(search_result.value().entry, NotNull()); - ASSERT_TRUE(search_result.value().entry->overlayable_item); - result_overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); - EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices)); - search_result = table_.FindResource(test::ParseNameOrDie("string/fiz")); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); @@ -1028,7 +1017,7 @@ TEST_F(ResourceParserTest, ParseOverlayableBadPolicyError) { TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) { std::string input = R"( <overlayable name="Name"> - <policy type="vendor|product_services"> + <policy type="vendor|public"> <item type="string" name="foo" /> </policy> <policy type="product|system"> @@ -1044,7 +1033,7 @@ TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) { OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor - | OverlayableItem::Policy::kProductServices)); + | OverlayableItem::Policy::kPublic)); search_result = table_.FindResource(test::ParseNameOrDie("string/bar")); ASSERT_TRUE(search_result); @@ -1139,7 +1128,7 @@ TEST_F(ResourceParserTest, NestPolicyInOverlayableError) { std::string input = R"( <overlayable name="Name"> <policy type="vendor|product"> - <policy type="product_services"> + <policy type="public"> <item type="string" name="foo" /> </policy> </policy> diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h index eaf6a47a15fd..7ca99ea42b50 100644 --- a/tools/aapt2/ResourceTable.h +++ b/tools/aapt2/ResourceTable.h @@ -92,9 +92,6 @@ struct OverlayableItem { // The resource can be overlaid by any overlay on the product partition. kProduct = 0x08, - - // The resource can be overlaid by any overlay on the product services partition. - kProductServices = 0x10 }; std::shared_ptr<Overlayable> overlayable; diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp index a733134f123c..b97dc6b205ca 100644 --- a/tools/aapt2/ResourceTable_test.cpp +++ b/tools/aapt2/ResourceTable_test.cpp @@ -248,7 +248,7 @@ TEST(ResourceTableTest, SetOverlayable) { Source("res/values/overlayable.xml", 40)); OverlayableItem overlayable_item(overlayable); overlayable_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_item.policies |= OverlayableItem::Policy::kProductServices; + overlayable_item.policies |= OverlayableItem::Policy::kVendor; overlayable_item.comment = "comment"; overlayable_item.source = Source("res/values/overlayable.xml", 42); @@ -265,7 +265,7 @@ TEST(ResourceTableTest, SetOverlayable) { EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40); EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kProductServices)); + | OverlayableItem::Policy::kVendor)); ASSERT_THAT(result_overlayable_item.comment, StrEq("comment")); EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml")); EXPECT_THAT(result_overlayable_item.source.line, 42); diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index da541be9502b..73b568e77689 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -155,7 +155,6 @@ message OverlayableItem { SYSTEM = 1; VENDOR = 2; PRODUCT = 3; - PRODUCT_SERVICES = 4; } // The location of the <item> declaration in source. diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index 7d4c6f348403..40aaa05c2b30 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -473,10 +473,6 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { & ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) { policies |= OverlayableItem::Policy::kProduct; } - if (policy_header->policy_flags - & ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) { - policies |= OverlayableItem::Policy::kProductServices; - } const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>( ((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize)); diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index c4ecbafc008b..9d341cc1ca4a 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -485,9 +485,6 @@ class PackageFlattener { if (item.policies & OverlayableItem::Policy::kProduct) { policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; } - if (item.policies & OverlayableItem::Policy::kProductServices) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION; - } } auto policy = overlayable_chunk->policy_ids.find(policy_flags); diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index 18fecf60c977..ddc117399390 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -660,12 +660,10 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { OverlayableItem overlayable_item_zero(overlayable); overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; - overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices; std::string name_one = "com.app.test:integer/overlayable_one_item"; OverlayableItem overlayable_item_one(overlayable); overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; - overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices; std::string name_two = "com.app.test:integer/overlayable_two_item"; OverlayableItem overlayable_item_two(overlayable); @@ -698,16 +696,14 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { ASSERT_TRUE(search_result.value().entry->overlayable_item); OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kProductServices); + | OverlayableItem::Policy::kProduct); search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); - EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic - | OverlayableItem::Policy::kProductServices); + EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); ASSERT_TRUE(search_result); @@ -735,13 +731,11 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { OverlayableItem overlayable_item_zero(group); overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; - overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices; auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization"); std::string name_one = "com.app.test:integer/overlayable_one"; OverlayableItem overlayable_item_one(group_one); overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; - overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices; std::string name_two = "com.app.test:integer/overlayable_two"; OverlayableItem overlayable_item_two(group); @@ -773,8 +767,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem - | OverlayableItem::Policy::kProduct - | OverlayableItem::Policy::kProductServices); + | OverlayableItem::Policy::kProduct); search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); @@ -782,8 +775,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic - | OverlayableItem::Policy::kProductServices); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic); search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); ASSERT_TRUE(search_result); ASSERT_THAT(search_result.value().entry, NotNull()); diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 6b5746d63bf8..aff1b391f861 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -390,9 +390,6 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, case pb::OverlayableItem::PRODUCT: out_overlayable->policies |= OverlayableItem::Policy::kProduct; break; - case pb::OverlayableItem::PRODUCT_SERVICES: - out_overlayable->policies |= OverlayableItem::Policy::kProductServices; - break; default: *out_error = "unknown overlayable policy"; return false; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index 76fbb464b62a..b549e2369f98 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -303,9 +303,6 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item if (overlayable_item.policies & OverlayableItem::Policy::kProduct) { pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT); } - if (overlayable_item.policies & OverlayableItem::Policy::kProductServices) { - pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT_SERVICES); - } if (overlayable_item.policies & OverlayableItem::Policy::kSystem) { pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM); } diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index 4a3c1b86236e..cce3939704cf 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -519,7 +519,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>( "TaskBar", "overlay://theme")); - overlayable_item_bar.policies |= OverlayableItem::Policy::kProductServices; + overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic; overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor; OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>( @@ -565,7 +565,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar")); EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); - EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices + EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic | OverlayableItem::Policy::kVendor)); search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz")); diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp index 921d634e583e..ad3674e16774 100644 --- a/tools/aapt2/link/TableMerger_test.cpp +++ b/tools/aapt2/link/TableMerger_test.cpp @@ -484,7 +484,7 @@ TEST_F(TableMergerTest, SetOverlayableLater) { OverlayableItem overlayable_item(overlayable); overlayable_item.policies |= OverlayableItem::Policy::kPublic; - overlayable_item.policies |= OverlayableItem::Policy::kProductServices; + overlayable_item.policies |= OverlayableItem::Policy::kSystem; std::unique_ptr<ResourceTable> table_b = test::ResourceTableBuilder() .SetPackageId("com.app.a", 0x7f) @@ -506,7 +506,7 @@ TEST_F(TableMergerTest, SetOverlayableLater) { EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources")); EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization")); EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic - | OverlayableItem::Policy::kProductServices)); + | OverlayableItem::Policy::kSystem)); } TEST_F(TableMergerTest, SameResourceDifferentNameFail) { diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 840af5d5cd06..35fba3dcf7cf 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -16,6 +16,7 @@ package android.net.wifi; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; @@ -470,6 +471,7 @@ public class WifiInfo implements Parcelable { } /** {@hide} */ + @SystemApi public boolean isOsuAp() { return mOsuAp; } diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 559f4ad8264e..801342dc0c6e 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -236,9 +236,11 @@ public class WifiManager { public static final int WIFI_CREDENTIAL_FORGOT = 1; /** @hide */ + @SystemApi public static final int PASSPOINT_HOME_NETWORK = 0; /** @hide */ + @SystemApi public static final int PASSPOINT_ROAMING_NETWORK = 1; /** @@ -1219,7 +1221,11 @@ public class WifiManager { * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs( @NonNull List<ScanResult> scanResults) { List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>(); @@ -1258,7 +1264,11 @@ public class WifiManager { * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders( List<ScanResult> scanResults) { try { @@ -1281,7 +1291,11 @@ public class WifiManager { * @throws UnsupportedOperationException if Passpoint is not enabled on the device. * @hide */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders( @NonNull Set<OsuProvider> osuProviders) { try { @@ -1727,7 +1741,13 @@ public class WifiManager { * @param fqdn The FQDN of the Passpoint configuration to be removed * @throws IllegalArgumentException if no configuration is associated with the given FQDN. * @throws UnsupportedOperationException if Passpoint is not enabled on the device. + * @deprecated This is no longer supported. */ + @Deprecated + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) public void removePasspointConfiguration(String fqdn) { try { if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) { @@ -1745,7 +1765,13 @@ public class WifiManager { * * @return A list of {@link PasspointConfiguration} * @throws UnsupportedOperationException if Passpoint is not enabled on the device. + * @deprecated This is no longer supported. */ + @Deprecated + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) public List<PasspointConfiguration> getPasspointConfigurations() { try { return mService.getPasspointConfigurations(); @@ -4323,6 +4349,11 @@ public class WifiManager { * @param callback {@link ProvisioningCallback} for updates regarding provisioning flow * @hide */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_SETUP_WIZARD + }) public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback, @Nullable Handler handler) { Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper(); diff --git a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java index 955e040a46f1..b8175d2338ec 100644 --- a/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkAgentSpecifier.java @@ -168,8 +168,9 @@ public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements @Override public String toString() { StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier ["); - sb.append("WifiConfiguration=").append( - mWifiConfiguration == null ? null : mWifiConfiguration.configKey()) + sb.append("WifiConfiguration=") + .append(", SSID=").append(mWifiConfiguration.SSID) + .append(", BSSID=").append(mWifiConfiguration.BSSID) .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid) .append("]"); return sb.toString(); diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java index 4348399b404b..6e4eeef4dd55 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java +++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java @@ -162,11 +162,11 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc @Override public String toString() { return new StringBuilder() - .append("WifiNetworkSpecifierWifiNetworkSpecifier [") + .append("WifiNetworkSpecifier [") .append(", SSID Match pattern=").append(ssidPatternMatcher) .append(", BSSID Match pattern=").append(bssidPatternMatcher) - .append(", WifiConfiguration=").append( - wifiConfiguration == null ? null : wifiConfiguration.configKey()) + .append(", SSID=").append(wifiConfiguration.SSID) + .append(", BSSID=").append(wifiConfiguration.BSSID) .append(", requestorUid=").append(requestorUid) .append("]") .toString(); diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java index 760f1e6bc5e2..3c90eb763e81 100644 --- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java +++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java @@ -130,7 +130,8 @@ public final class WifiNetworkSuggestion implements Parcelable { @Override public String toString() { StringBuilder sb = new StringBuilder("WifiNetworkSuggestion [") - .append(", WifiConfiguration=").append(wifiConfiguration) + .append(", SSID=").append(wifiConfiguration.SSID) + .append(", BSSID=").append(wifiConfiguration.BSSID) .append(", isAppInteractionRequired=").append(isAppInteractionRequired) .append(", isUserInteractionRequired=").append(isUserInteractionRequired) .append(", suggestorUid=").append(suggestorUid) diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java index 6d82ca152202..f91790f5b3b1 100644 --- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java +++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java @@ -16,6 +16,7 @@ package android.net.wifi.hotspot2; +import android.annotation.SystemApi; import android.graphics.drawable.Icon; import android.net.Uri; import android.net.wifi.WifiSsid; @@ -36,16 +37,19 @@ import java.util.Objects; * * @hide */ +@SystemApi public final class OsuProvider implements Parcelable { /** * OSU (Online Sign-Up) method: OMA DM (Open Mobile Alliance Device Management). * For more info, refer to Section 8.3 of the Hotspot 2.0 Release 2 Technical Specification. + * @hide */ public static final int METHOD_OMA_DM = 0; /** * OSU (Online Sign-Up) method: SOAP XML SPP (Subscription Provisioning Protocol). * For more info, refer to Section 8.4 of the Hotspot 2.0 Release 2 Technical Specification. + * @hide */ public static final int METHOD_SOAP_XML_SPP = 1; @@ -84,6 +88,7 @@ public final class OsuProvider implements Parcelable { */ private final Icon mIcon; + /** @hide */ public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames, String serviceDescription, Uri serverUri, String nai, List<Integer> methodList, Icon icon) { @@ -104,6 +109,7 @@ public final class OsuProvider implements Parcelable { * Copy constructor. * * @param source The source to copy from + * @hide */ public OsuProvider(OsuProvider source) { if (source == null) { @@ -130,10 +136,12 @@ public final class OsuProvider implements Parcelable { mIcon = source.mIcon; } + /** @hide */ public WifiSsid getOsuSsid() { return mOsuSsid; } + /** @hide */ public void setOsuSsid(WifiSsid osuSsid) { mOsuSsid = osuSsid; } @@ -162,10 +170,12 @@ public final class OsuProvider implements Parcelable { return mFriendlyNames.get(mFriendlyNames.keySet().stream().findFirst().get()); } + /** @hide */ public Map<String, String> getFriendlyNameList() { return mFriendlyNames; } + /** @hide */ public String getServiceDescription() { return mServiceDescription; } @@ -174,14 +184,17 @@ public final class OsuProvider implements Parcelable { return mServerUri; } + /** @hide */ public String getNetworkAccessIdentifier() { return mNetworkAccessIdentifier; } + /** @hide */ public List<Integer> getMethodList() { return mMethodList; } + /** @hide */ public Icon getIcon() { return mIcon; } diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java index a62d63cd8910..1ee874a9698b 100644 --- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java +++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java @@ -16,6 +16,7 @@ package android.net.wifi.hotspot2; +import android.annotation.SystemApi; import android.net.wifi.WifiManager; import android.os.Handler; @@ -25,6 +26,7 @@ import android.os.Handler; * * @hide */ +@SystemApi public abstract class ProvisioningCallback { /** |